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::{
  167    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  168    update_settings_file,
  169};
  170use smallvec::{SmallVec, smallvec};
  171use snippet::Snippet;
  172use std::{
  173    any::{Any, TypeId},
  174    borrow::Cow,
  175    cell::{OnceCell, RefCell},
  176    cmp::{self, Ordering, Reverse},
  177    iter::{self, Peekable},
  178    mem,
  179    num::NonZeroU32,
  180    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  181    path::{Path, PathBuf},
  182    rc::Rc,
  183    sync::Arc,
  184    time::{Duration, Instant},
  185};
  186use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  187use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  188use theme::{
  189    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  190    observe_buffer_font_size_adjustment,
  191};
  192use ui::{
  193    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  194    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  195};
  196use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  197use workspace::{
  198    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  199    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  200    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  201    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  202    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  203    searchable::SearchEvent,
  204};
  205
  206use crate::{
  207    code_context_menus::CompletionsMenuSource,
  208    editor_settings::MultiCursorModifier,
  209    hover_links::{find_url, find_url_from_range},
  210    inlays::{
  211        InlineValueCache,
  212        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  213    },
  214    scroll::{ScrollOffset, ScrollPixelOffset},
  215    selections_collection::resolve_selections_wrapping_blocks,
  216    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  217};
  218
  219pub const FILE_HEADER_HEIGHT: u32 = 2;
  220pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  221const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  222const MAX_LINE_LEN: usize = 1024;
  223const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  224const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  225pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  226#[doc(hidden)]
  227pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  228pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  229
  230pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  233pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  234
  235pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  236pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  237pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  238
  239pub type RenderDiffHunkControlsFn = Arc<
  240    dyn Fn(
  241        u32,
  242        &DiffHunkStatus,
  243        Range<Anchor>,
  244        bool,
  245        Pixels,
  246        &Entity<Editor>,
  247        &mut Window,
  248        &mut App,
  249    ) -> AnyElement,
  250>;
  251
  252enum ReportEditorEvent {
  253    Saved { auto_saved: bool },
  254    EditorOpened,
  255    Closed,
  256}
  257
  258impl ReportEditorEvent {
  259    pub fn event_type(&self) -> &'static str {
  260        match self {
  261            Self::Saved { .. } => "Editor Saved",
  262            Self::EditorOpened => "Editor Opened",
  263            Self::Closed => "Editor Closed",
  264        }
  265    }
  266}
  267
  268pub enum ActiveDebugLine {}
  269pub enum DebugStackFrameLine {}
  270enum DocumentHighlightRead {}
  271enum DocumentHighlightWrite {}
  272enum InputComposition {}
  273pub enum PendingInput {}
  274enum SelectedTextHighlight {}
  275
  276pub enum ConflictsOuter {}
  277pub enum ConflictsOurs {}
  278pub enum ConflictsTheirs {}
  279pub enum ConflictsOursMarker {}
  280pub enum ConflictsTheirsMarker {}
  281
  282#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  283pub enum Navigated {
  284    Yes,
  285    No,
  286}
  287
  288impl Navigated {
  289    pub fn from_bool(yes: bool) -> Navigated {
  290        if yes { Navigated::Yes } else { Navigated::No }
  291    }
  292}
  293
  294#[derive(Debug, Clone, PartialEq, Eq)]
  295enum DisplayDiffHunk {
  296    Folded {
  297        display_row: DisplayRow,
  298    },
  299    Unfolded {
  300        is_created_file: bool,
  301        diff_base_byte_range: Range<usize>,
  302        display_row_range: Range<DisplayRow>,
  303        multi_buffer_range: Range<Anchor>,
  304        status: DiffHunkStatus,
  305    },
  306}
  307
  308pub enum HideMouseCursorOrigin {
  309    TypingAction,
  310    MovementAction,
  311}
  312
  313pub fn init_settings(cx: &mut App) {
  314    EditorSettings::register(cx);
  315}
  316
  317pub fn init(cx: &mut App) {
  318    init_settings(cx);
  319
  320    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  321
  322    workspace::register_project_item::<Editor>(cx);
  323    workspace::FollowableViewRegistry::register::<Editor>(cx);
  324    workspace::register_serializable_item::<Editor>(cx);
  325
  326    cx.observe_new(
  327        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  328            workspace.register_action(Editor::new_file);
  329            workspace.register_action(Editor::new_file_split);
  330            workspace.register_action(Editor::new_file_vertical);
  331            workspace.register_action(Editor::new_file_horizontal);
  332            workspace.register_action(Editor::cancel_language_server_work);
  333            workspace.register_action(Editor::toggle_focus);
  334        },
  335    )
  336    .detach();
  337
  338    cx.on_action(move |_: &workspace::NewFile, cx| {
  339        let app_state = workspace::AppState::global(cx);
  340        if let Some(app_state) = app_state.upgrade() {
  341            workspace::open_new(
  342                Default::default(),
  343                app_state,
  344                cx,
  345                |workspace, window, cx| {
  346                    Editor::new_file(workspace, &Default::default(), window, cx)
  347                },
  348            )
  349            .detach();
  350        }
  351    });
  352    cx.on_action(move |_: &workspace::NewWindow, cx| {
  353        let app_state = workspace::AppState::global(cx);
  354        if let Some(app_state) = app_state.upgrade() {
  355            workspace::open_new(
  356                Default::default(),
  357                app_state,
  358                cx,
  359                |workspace, window, cx| {
  360                    cx.activate(true);
  361                    Editor::new_file(workspace, &Default::default(), window, cx)
  362                },
  363            )
  364            .detach();
  365        }
  366    });
  367}
  368
  369pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  370    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  371}
  372
  373pub trait DiagnosticRenderer {
  374    fn render_group(
  375        &self,
  376        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  377        buffer_id: BufferId,
  378        snapshot: EditorSnapshot,
  379        editor: WeakEntity<Editor>,
  380        cx: &mut App,
  381    ) -> Vec<BlockProperties<Anchor>>;
  382
  383    fn render_hover(
  384        &self,
  385        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  386        range: Range<Point>,
  387        buffer_id: BufferId,
  388        cx: &mut App,
  389    ) -> Option<Entity<markdown::Markdown>>;
  390
  391    fn open_link(
  392        &self,
  393        editor: &mut Editor,
  394        link: SharedString,
  395        window: &mut Window,
  396        cx: &mut Context<Editor>,
  397    );
  398}
  399
  400pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  401
  402impl GlobalDiagnosticRenderer {
  403    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  404        cx.try_global::<Self>().map(|g| g.0.clone())
  405    }
  406}
  407
  408impl gpui::Global for GlobalDiagnosticRenderer {}
  409pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  410    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  411}
  412
  413pub struct SearchWithinRange;
  414
  415trait InvalidationRegion {
  416    fn ranges(&self) -> &[Range<Anchor>];
  417}
  418
  419#[derive(Clone, Debug, PartialEq)]
  420pub enum SelectPhase {
  421    Begin {
  422        position: DisplayPoint,
  423        add: bool,
  424        click_count: usize,
  425    },
  426    BeginColumnar {
  427        position: DisplayPoint,
  428        reset: bool,
  429        mode: ColumnarMode,
  430        goal_column: u32,
  431    },
  432    Extend {
  433        position: DisplayPoint,
  434        click_count: usize,
  435    },
  436    Update {
  437        position: DisplayPoint,
  438        goal_column: u32,
  439        scroll_delta: gpui::Point<f32>,
  440    },
  441    End,
  442}
  443
  444#[derive(Clone, Debug, PartialEq)]
  445pub enum ColumnarMode {
  446    FromMouse,
  447    FromSelection,
  448}
  449
  450#[derive(Clone, Debug)]
  451pub enum SelectMode {
  452    Character,
  453    Word(Range<Anchor>),
  454    Line(Range<Anchor>),
  455    All,
  456}
  457
  458#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  459pub enum SizingBehavior {
  460    /// The editor will layout itself using `size_full` and will include the vertical
  461    /// scroll margin as requested by user settings.
  462    #[default]
  463    Default,
  464    /// The editor will layout itself using `size_full`, but will not have any
  465    /// vertical overscroll.
  466    ExcludeOverscrollMargin,
  467    /// The editor will request a vertical size according to its content and will be
  468    /// layouted without a vertical scroll margin.
  469    SizeByContent,
  470}
  471
  472#[derive(Clone, PartialEq, Eq, Debug)]
  473pub enum EditorMode {
  474    SingleLine,
  475    AutoHeight {
  476        min_lines: usize,
  477        max_lines: Option<usize>,
  478    },
  479    Full {
  480        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  481        scale_ui_elements_with_buffer_font_size: bool,
  482        /// When set to `true`, the editor will render a background for the active line.
  483        show_active_line_background: bool,
  484        /// Determines the sizing behavior for this editor
  485        sizing_behavior: SizingBehavior,
  486    },
  487    Minimap {
  488        parent: WeakEntity<Editor>,
  489    },
  490}
  491
  492impl EditorMode {
  493    pub fn full() -> Self {
  494        Self::Full {
  495            scale_ui_elements_with_buffer_font_size: true,
  496            show_active_line_background: true,
  497            sizing_behavior: SizingBehavior::Default,
  498        }
  499    }
  500
  501    #[inline]
  502    pub fn is_full(&self) -> bool {
  503        matches!(self, Self::Full { .. })
  504    }
  505
  506    #[inline]
  507    pub fn is_single_line(&self) -> bool {
  508        matches!(self, Self::SingleLine { .. })
  509    }
  510
  511    #[inline]
  512    fn is_minimap(&self) -> bool {
  513        matches!(self, Self::Minimap { .. })
  514    }
  515}
  516
  517#[derive(Copy, Clone, Debug)]
  518pub enum SoftWrap {
  519    /// Prefer not to wrap at all.
  520    ///
  521    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  522    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  523    GitDiff,
  524    /// Prefer a single line generally, unless an overly long line is encountered.
  525    None,
  526    /// Soft wrap lines that exceed the editor width.
  527    EditorWidth,
  528    /// Soft wrap lines at the preferred line length.
  529    Column(u32),
  530    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  531    Bounded(u32),
  532}
  533
  534#[derive(Clone)]
  535pub struct EditorStyle {
  536    pub background: Hsla,
  537    pub border: Hsla,
  538    pub local_player: PlayerColor,
  539    pub text: TextStyle,
  540    pub scrollbar_width: Pixels,
  541    pub syntax: Arc<SyntaxTheme>,
  542    pub status: StatusColors,
  543    pub inlay_hints_style: HighlightStyle,
  544    pub edit_prediction_styles: EditPredictionStyles,
  545    pub unnecessary_code_fade: f32,
  546    pub show_underlines: bool,
  547}
  548
  549impl Default for EditorStyle {
  550    fn default() -> Self {
  551        Self {
  552            background: Hsla::default(),
  553            border: Hsla::default(),
  554            local_player: PlayerColor::default(),
  555            text: TextStyle::default(),
  556            scrollbar_width: Pixels::default(),
  557            syntax: Default::default(),
  558            // HACK: Status colors don't have a real default.
  559            // We should look into removing the status colors from the editor
  560            // style and retrieve them directly from the theme.
  561            status: StatusColors::dark(),
  562            inlay_hints_style: HighlightStyle::default(),
  563            edit_prediction_styles: EditPredictionStyles {
  564                insertion: HighlightStyle::default(),
  565                whitespace: HighlightStyle::default(),
  566            },
  567            unnecessary_code_fade: Default::default(),
  568            show_underlines: true,
  569        }
  570    }
  571}
  572
  573pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  574    let show_background = language_settings::language_settings(None, None, cx)
  575        .inlay_hints
  576        .show_background;
  577
  578    let mut style = cx.theme().syntax().get("hint");
  579
  580    if style.color.is_none() {
  581        style.color = Some(cx.theme().status().hint);
  582    }
  583
  584    if !show_background {
  585        style.background_color = None;
  586        return style;
  587    }
  588
  589    if style.background_color.is_none() {
  590        style.background_color = Some(cx.theme().status().hint_background);
  591    }
  592
  593    style
  594}
  595
  596pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  597    EditPredictionStyles {
  598        insertion: HighlightStyle {
  599            color: Some(cx.theme().status().predictive),
  600            ..HighlightStyle::default()
  601        },
  602        whitespace: HighlightStyle {
  603            background_color: Some(cx.theme().status().created_background),
  604            ..HighlightStyle::default()
  605        },
  606    }
  607}
  608
  609type CompletionId = usize;
  610
  611pub(crate) enum EditDisplayMode {
  612    TabAccept,
  613    DiffPopover,
  614    Inline,
  615}
  616
  617enum EditPrediction {
  618    Edit {
  619        edits: Vec<(Range<Anchor>, String)>,
  620        edit_preview: Option<EditPreview>,
  621        display_mode: EditDisplayMode,
  622        snapshot: BufferSnapshot,
  623    },
  624    /// Move to a specific location in the active editor
  625    MoveWithin {
  626        target: Anchor,
  627        snapshot: BufferSnapshot,
  628    },
  629    /// Move to a specific location in a different editor (not the active one)
  630    MoveOutside {
  631        target: language::Anchor,
  632        snapshot: BufferSnapshot,
  633    },
  634}
  635
  636struct EditPredictionState {
  637    inlay_ids: Vec<InlayId>,
  638    completion: EditPrediction,
  639    completion_id: Option<SharedString>,
  640    invalidation_range: Option<Range<Anchor>>,
  641}
  642
  643enum EditPredictionSettings {
  644    Disabled,
  645    Enabled {
  646        show_in_menu: bool,
  647        preview_requires_modifier: bool,
  648    },
  649}
  650
  651enum EditPredictionHighlight {}
  652
  653#[derive(Debug, Clone)]
  654struct InlineDiagnostic {
  655    message: SharedString,
  656    group_id: usize,
  657    is_primary: bool,
  658    start: Point,
  659    severity: lsp::DiagnosticSeverity,
  660}
  661
  662pub enum MenuEditPredictionsPolicy {
  663    Never,
  664    ByProvider,
  665}
  666
  667pub enum EditPredictionPreview {
  668    /// Modifier is not pressed
  669    Inactive { released_too_fast: bool },
  670    /// Modifier pressed
  671    Active {
  672        since: Instant,
  673        previous_scroll_position: Option<ScrollAnchor>,
  674    },
  675}
  676
  677impl EditPredictionPreview {
  678    pub fn released_too_fast(&self) -> bool {
  679        match self {
  680            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  681            EditPredictionPreview::Active { .. } => false,
  682        }
  683    }
  684
  685    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  686        if let EditPredictionPreview::Active {
  687            previous_scroll_position,
  688            ..
  689        } = self
  690        {
  691            *previous_scroll_position = scroll_position;
  692        }
  693    }
  694}
  695
  696pub struct ContextMenuOptions {
  697    pub min_entries_visible: usize,
  698    pub max_entries_visible: usize,
  699    pub placement: Option<ContextMenuPlacement>,
  700}
  701
  702#[derive(Debug, Clone, PartialEq, Eq)]
  703pub enum ContextMenuPlacement {
  704    Above,
  705    Below,
  706}
  707
  708#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  709struct EditorActionId(usize);
  710
  711impl EditorActionId {
  712    pub fn post_inc(&mut self) -> Self {
  713        let answer = self.0;
  714
  715        *self = Self(answer + 1);
  716
  717        Self(answer)
  718    }
  719}
  720
  721// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  722// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  723
  724type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  725type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  726
  727#[derive(Default)]
  728struct ScrollbarMarkerState {
  729    scrollbar_size: Size<Pixels>,
  730    dirty: bool,
  731    markers: Arc<[PaintQuad]>,
  732    pending_refresh: Option<Task<Result<()>>>,
  733}
  734
  735impl ScrollbarMarkerState {
  736    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  737        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  738    }
  739}
  740
  741#[derive(Clone, Copy, PartialEq, Eq)]
  742pub enum MinimapVisibility {
  743    Disabled,
  744    Enabled {
  745        /// The configuration currently present in the users settings.
  746        setting_configuration: bool,
  747        /// Whether to override the currently set visibility from the users setting.
  748        toggle_override: bool,
  749    },
  750}
  751
  752impl MinimapVisibility {
  753    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  754        if mode.is_full() {
  755            Self::Enabled {
  756                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  757                toggle_override: false,
  758            }
  759        } else {
  760            Self::Disabled
  761        }
  762    }
  763
  764    fn hidden(&self) -> Self {
  765        match *self {
  766            Self::Enabled {
  767                setting_configuration,
  768                ..
  769            } => Self::Enabled {
  770                setting_configuration,
  771                toggle_override: setting_configuration,
  772            },
  773            Self::Disabled => Self::Disabled,
  774        }
  775    }
  776
  777    fn disabled(&self) -> bool {
  778        matches!(*self, Self::Disabled)
  779    }
  780
  781    fn settings_visibility(&self) -> bool {
  782        match *self {
  783            Self::Enabled {
  784                setting_configuration,
  785                ..
  786            } => setting_configuration,
  787            _ => false,
  788        }
  789    }
  790
  791    fn visible(&self) -> bool {
  792        match *self {
  793            Self::Enabled {
  794                setting_configuration,
  795                toggle_override,
  796            } => setting_configuration ^ toggle_override,
  797            _ => false,
  798        }
  799    }
  800
  801    fn toggle_visibility(&self) -> Self {
  802        match *self {
  803            Self::Enabled {
  804                toggle_override,
  805                setting_configuration,
  806            } => Self::Enabled {
  807                setting_configuration,
  808                toggle_override: !toggle_override,
  809            },
  810            Self::Disabled => Self::Disabled,
  811        }
  812    }
  813}
  814
  815#[derive(Clone, Debug)]
  816struct RunnableTasks {
  817    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  818    offset: multi_buffer::Anchor,
  819    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  820    column: u32,
  821    // Values of all named captures, including those starting with '_'
  822    extra_variables: HashMap<String, String>,
  823    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  824    context_range: Range<BufferOffset>,
  825}
  826
  827impl RunnableTasks {
  828    fn resolve<'a>(
  829        &'a self,
  830        cx: &'a task::TaskContext,
  831    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  832        self.templates.iter().filter_map(|(kind, template)| {
  833            template
  834                .resolve_task(&kind.to_id_base(), cx)
  835                .map(|task| (kind.clone(), task))
  836        })
  837    }
  838}
  839
  840#[derive(Clone)]
  841pub struct ResolvedTasks {
  842    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  843    position: Anchor,
  844}
  845
  846#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  847struct BufferOffset(usize);
  848
  849/// Addons allow storing per-editor state in other crates (e.g. Vim)
  850pub trait Addon: 'static {
  851    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  852
  853    fn render_buffer_header_controls(
  854        &self,
  855        _: &ExcerptInfo,
  856        _: &Window,
  857        _: &App,
  858    ) -> Option<AnyElement> {
  859        None
  860    }
  861
  862    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  863        None
  864    }
  865
  866    fn to_any(&self) -> &dyn std::any::Any;
  867
  868    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  869        None
  870    }
  871}
  872
  873struct ChangeLocation {
  874    current: Option<Vec<Anchor>>,
  875    original: Vec<Anchor>,
  876}
  877impl ChangeLocation {
  878    fn locations(&self) -> &[Anchor] {
  879        self.current.as_ref().unwrap_or(&self.original)
  880    }
  881}
  882
  883/// A set of caret positions, registered when the editor was edited.
  884pub struct ChangeList {
  885    changes: Vec<ChangeLocation>,
  886    /// Currently "selected" change.
  887    position: Option<usize>,
  888}
  889
  890impl ChangeList {
  891    pub fn new() -> Self {
  892        Self {
  893            changes: Vec::new(),
  894            position: None,
  895        }
  896    }
  897
  898    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  899    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  900    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  901        if self.changes.is_empty() {
  902            return None;
  903        }
  904
  905        let prev = self.position.unwrap_or(self.changes.len());
  906        let next = if direction == Direction::Prev {
  907            prev.saturating_sub(count)
  908        } else {
  909            (prev + count).min(self.changes.len() - 1)
  910        };
  911        self.position = Some(next);
  912        self.changes.get(next).map(|change| change.locations())
  913    }
  914
  915    /// Adds a new change to the list, resetting the change list position.
  916    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  917        self.position.take();
  918        if let Some(last) = self.changes.last_mut()
  919            && group
  920        {
  921            last.current = Some(new_positions)
  922        } else {
  923            self.changes.push(ChangeLocation {
  924                original: new_positions,
  925                current: None,
  926            });
  927        }
  928    }
  929
  930    pub fn last(&self) -> Option<&[Anchor]> {
  931        self.changes.last().map(|change| change.locations())
  932    }
  933
  934    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  935        self.changes.last().map(|change| change.original.as_slice())
  936    }
  937
  938    pub fn invert_last_group(&mut self) {
  939        if let Some(last) = self.changes.last_mut()
  940            && let Some(current) = last.current.as_mut()
  941        {
  942            mem::swap(&mut last.original, current);
  943        }
  944    }
  945}
  946
  947#[derive(Clone)]
  948struct InlineBlamePopoverState {
  949    scroll_handle: ScrollHandle,
  950    commit_message: Option<ParsedCommitMessage>,
  951    markdown: Entity<Markdown>,
  952}
  953
  954struct InlineBlamePopover {
  955    position: gpui::Point<Pixels>,
  956    hide_task: Option<Task<()>>,
  957    popover_bounds: Option<Bounds<Pixels>>,
  958    popover_state: InlineBlamePopoverState,
  959    keyboard_grace: bool,
  960}
  961
  962enum SelectionDragState {
  963    /// State when no drag related activity is detected.
  964    None,
  965    /// State when the mouse is down on a selection that is about to be dragged.
  966    ReadyToDrag {
  967        selection: Selection<Anchor>,
  968        click_position: gpui::Point<Pixels>,
  969        mouse_down_time: Instant,
  970    },
  971    /// State when the mouse is dragging the selection in the editor.
  972    Dragging {
  973        selection: Selection<Anchor>,
  974        drop_cursor: Selection<Anchor>,
  975        hide_drop_cursor: bool,
  976    },
  977}
  978
  979enum ColumnarSelectionState {
  980    FromMouse {
  981        selection_tail: Anchor,
  982        display_point: Option<DisplayPoint>,
  983    },
  984    FromSelection {
  985        selection_tail: Anchor,
  986    },
  987}
  988
  989/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  990/// a breakpoint on them.
  991#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  992struct PhantomBreakpointIndicator {
  993    display_row: DisplayRow,
  994    /// There's a small debounce between hovering over the line and showing the indicator.
  995    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  996    is_active: bool,
  997    collides_with_existing_breakpoint: bool,
  998}
  999
 1000/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1001///
 1002/// See the [module level documentation](self) for more information.
 1003pub struct Editor {
 1004    focus_handle: FocusHandle,
 1005    last_focused_descendant: Option<WeakFocusHandle>,
 1006    /// The text buffer being edited
 1007    buffer: Entity<MultiBuffer>,
 1008    /// Map of how text in the buffer should be displayed.
 1009    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1010    pub display_map: Entity<DisplayMap>,
 1011    placeholder_display_map: Option<Entity<DisplayMap>>,
 1012    pub selections: SelectionsCollection,
 1013    pub scroll_manager: ScrollManager,
 1014    /// When inline assist editors are linked, they all render cursors because
 1015    /// typing enters text into each of them, even the ones that aren't focused.
 1016    pub(crate) show_cursor_when_unfocused: bool,
 1017    columnar_selection_state: Option<ColumnarSelectionState>,
 1018    add_selections_state: Option<AddSelectionsState>,
 1019    select_next_state: Option<SelectNextState>,
 1020    select_prev_state: Option<SelectNextState>,
 1021    selection_history: SelectionHistory,
 1022    defer_selection_effects: bool,
 1023    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1024    autoclose_regions: Vec<AutocloseRegion>,
 1025    snippet_stack: InvalidationStack<SnippetState>,
 1026    select_syntax_node_history: SelectSyntaxNodeHistory,
 1027    ime_transaction: Option<TransactionId>,
 1028    pub diagnostics_max_severity: DiagnosticSeverity,
 1029    active_diagnostics: ActiveDiagnostic,
 1030    show_inline_diagnostics: bool,
 1031    inline_diagnostics_update: Task<()>,
 1032    inline_diagnostics_enabled: bool,
 1033    diagnostics_enabled: bool,
 1034    word_completions_enabled: bool,
 1035    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1036    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1037    hard_wrap: Option<usize>,
 1038    project: Option<Entity<Project>>,
 1039    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1040    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1041    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1042    blink_manager: Entity<BlinkManager>,
 1043    show_cursor_names: bool,
 1044    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1045    pub show_local_selections: bool,
 1046    mode: EditorMode,
 1047    show_breadcrumbs: bool,
 1048    show_gutter: bool,
 1049    show_scrollbars: ScrollbarAxes,
 1050    minimap_visibility: MinimapVisibility,
 1051    offset_content: bool,
 1052    disable_expand_excerpt_buttons: bool,
 1053    show_line_numbers: Option<bool>,
 1054    use_relative_line_numbers: Option<bool>,
 1055    show_git_diff_gutter: Option<bool>,
 1056    show_code_actions: Option<bool>,
 1057    show_runnables: Option<bool>,
 1058    show_breakpoints: Option<bool>,
 1059    show_wrap_guides: Option<bool>,
 1060    show_indent_guides: Option<bool>,
 1061    highlight_order: usize,
 1062    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1063    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1064    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1065    scrollbar_marker_state: ScrollbarMarkerState,
 1066    active_indent_guides_state: ActiveIndentGuidesState,
 1067    nav_history: Option<ItemNavHistory>,
 1068    context_menu: RefCell<Option<CodeContextMenu>>,
 1069    context_menu_options: Option<ContextMenuOptions>,
 1070    mouse_context_menu: Option<MouseContextMenu>,
 1071    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1072    inline_blame_popover: Option<InlineBlamePopover>,
 1073    inline_blame_popover_show_task: Option<Task<()>>,
 1074    signature_help_state: SignatureHelpState,
 1075    auto_signature_help: Option<bool>,
 1076    find_all_references_task_sources: Vec<Anchor>,
 1077    next_completion_id: CompletionId,
 1078    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1079    code_actions_task: Option<Task<Result<()>>>,
 1080    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1081    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1082    document_highlights_task: Option<Task<()>>,
 1083    linked_editing_range_task: Option<Task<Option<()>>>,
 1084    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1085    pending_rename: Option<RenameState>,
 1086    searchable: bool,
 1087    cursor_shape: CursorShape,
 1088    current_line_highlight: Option<CurrentLineHighlight>,
 1089    autoindent_mode: Option<AutoindentMode>,
 1090    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1091    input_enabled: bool,
 1092    use_modal_editing: bool,
 1093    read_only: bool,
 1094    leader_id: Option<CollaboratorId>,
 1095    remote_id: Option<ViewId>,
 1096    pub hover_state: HoverState,
 1097    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1098    gutter_hovered: bool,
 1099    hovered_link_state: Option<HoveredLinkState>,
 1100    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1101    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1102    active_edit_prediction: Option<EditPredictionState>,
 1103    /// Used to prevent flickering as the user types while the menu is open
 1104    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1105    edit_prediction_settings: EditPredictionSettings,
 1106    edit_predictions_hidden_for_vim_mode: bool,
 1107    show_edit_predictions_override: Option<bool>,
 1108    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1109    edit_prediction_preview: EditPredictionPreview,
 1110    edit_prediction_indent_conflict: bool,
 1111    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1112    next_inlay_id: usize,
 1113    next_color_inlay_id: usize,
 1114    _subscriptions: Vec<Subscription>,
 1115    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1116    gutter_dimensions: GutterDimensions,
 1117    style: Option<EditorStyle>,
 1118    text_style_refinement: Option<TextStyleRefinement>,
 1119    next_editor_action_id: EditorActionId,
 1120    editor_actions: Rc<
 1121        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1122    >,
 1123    use_autoclose: bool,
 1124    use_auto_surround: bool,
 1125    auto_replace_emoji_shortcode: bool,
 1126    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1127    show_git_blame_gutter: bool,
 1128    show_git_blame_inline: bool,
 1129    show_git_blame_inline_delay_task: Option<Task<()>>,
 1130    git_blame_inline_enabled: bool,
 1131    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1132    serialize_dirty_buffers: bool,
 1133    show_selection_menu: Option<bool>,
 1134    blame: Option<Entity<GitBlame>>,
 1135    blame_subscription: Option<Subscription>,
 1136    custom_context_menu: Option<
 1137        Box<
 1138            dyn 'static
 1139                + Fn(
 1140                    &mut Self,
 1141                    DisplayPoint,
 1142                    &mut Window,
 1143                    &mut Context<Self>,
 1144                ) -> Option<Entity<ui::ContextMenu>>,
 1145        >,
 1146    >,
 1147    last_bounds: Option<Bounds<Pixels>>,
 1148    last_position_map: Option<Rc<PositionMap>>,
 1149    expect_bounds_change: Option<Bounds<Pixels>>,
 1150    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1151    tasks_update_task: Option<Task<()>>,
 1152    breakpoint_store: Option<Entity<BreakpointStore>>,
 1153    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1154    hovered_diff_hunk_row: Option<DisplayRow>,
 1155    pull_diagnostics_task: Task<()>,
 1156    in_project_search: bool,
 1157    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1158    breadcrumb_header: Option<String>,
 1159    focused_block: Option<FocusedBlock>,
 1160    next_scroll_position: NextScrollCursorCenterTopBottom,
 1161    addons: HashMap<TypeId, Box<dyn Addon>>,
 1162    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1163    load_diff_task: Option<Shared<Task<()>>>,
 1164    /// Whether we are temporarily displaying a diff other than git's
 1165    temporary_diff_override: bool,
 1166    selection_mark_mode: bool,
 1167    toggle_fold_multiple_buffers: Task<()>,
 1168    _scroll_cursor_center_top_bottom_task: Task<()>,
 1169    serialize_selections: Task<()>,
 1170    serialize_folds: Task<()>,
 1171    mouse_cursor_hidden: bool,
 1172    minimap: Option<Entity<Self>>,
 1173    hide_mouse_mode: HideMouseMode,
 1174    pub change_list: ChangeList,
 1175    inline_value_cache: InlineValueCache,
 1176    selection_drag_state: SelectionDragState,
 1177    colors: Option<LspColorData>,
 1178    post_scroll_update: Task<()>,
 1179    refresh_colors_task: Task<()>,
 1180    inlay_hints: Option<LspInlayHintData>,
 1181    folding_newlines: Task<()>,
 1182    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1183}
 1184
 1185fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1186    if debounce_ms > 0 {
 1187        Some(Duration::from_millis(debounce_ms))
 1188    } else {
 1189        None
 1190    }
 1191}
 1192
 1193#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1194enum NextScrollCursorCenterTopBottom {
 1195    #[default]
 1196    Center,
 1197    Top,
 1198    Bottom,
 1199}
 1200
 1201impl NextScrollCursorCenterTopBottom {
 1202    fn next(&self) -> Self {
 1203        match self {
 1204            Self::Center => Self::Top,
 1205            Self::Top => Self::Bottom,
 1206            Self::Bottom => Self::Center,
 1207        }
 1208    }
 1209}
 1210
 1211#[derive(Clone)]
 1212pub struct EditorSnapshot {
 1213    pub mode: EditorMode,
 1214    show_gutter: bool,
 1215    show_line_numbers: Option<bool>,
 1216    show_git_diff_gutter: Option<bool>,
 1217    show_code_actions: Option<bool>,
 1218    show_runnables: Option<bool>,
 1219    show_breakpoints: Option<bool>,
 1220    git_blame_gutter_max_author_length: Option<usize>,
 1221    pub display_snapshot: DisplaySnapshot,
 1222    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1223    is_focused: bool,
 1224    scroll_anchor: ScrollAnchor,
 1225    ongoing_scroll: OngoingScroll,
 1226    current_line_highlight: CurrentLineHighlight,
 1227    gutter_hovered: bool,
 1228}
 1229
 1230#[derive(Default, Debug, Clone, Copy)]
 1231pub struct GutterDimensions {
 1232    pub left_padding: Pixels,
 1233    pub right_padding: Pixels,
 1234    pub width: Pixels,
 1235    pub margin: Pixels,
 1236    pub git_blame_entries_width: Option<Pixels>,
 1237}
 1238
 1239impl GutterDimensions {
 1240    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1241        Self {
 1242            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1243            ..Default::default()
 1244        }
 1245    }
 1246
 1247    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1248        -cx.text_system().descent(font_id, font_size)
 1249    }
 1250    /// The full width of the space taken up by the gutter.
 1251    pub fn full_width(&self) -> Pixels {
 1252        self.margin + self.width
 1253    }
 1254
 1255    /// The width of the space reserved for the fold indicators,
 1256    /// use alongside 'justify_end' and `gutter_width` to
 1257    /// right align content with the line numbers
 1258    pub fn fold_area_width(&self) -> Pixels {
 1259        self.margin + self.right_padding
 1260    }
 1261}
 1262
 1263struct CharacterDimensions {
 1264    em_width: Pixels,
 1265    em_advance: Pixels,
 1266    line_height: Pixels,
 1267}
 1268
 1269#[derive(Debug)]
 1270pub struct RemoteSelection {
 1271    pub replica_id: ReplicaId,
 1272    pub selection: Selection<Anchor>,
 1273    pub cursor_shape: CursorShape,
 1274    pub collaborator_id: CollaboratorId,
 1275    pub line_mode: bool,
 1276    pub user_name: Option<SharedString>,
 1277    pub color: PlayerColor,
 1278}
 1279
 1280#[derive(Clone, Debug)]
 1281struct SelectionHistoryEntry {
 1282    selections: Arc<[Selection<Anchor>]>,
 1283    select_next_state: Option<SelectNextState>,
 1284    select_prev_state: Option<SelectNextState>,
 1285    add_selections_state: Option<AddSelectionsState>,
 1286}
 1287
 1288#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1289enum SelectionHistoryMode {
 1290    Normal,
 1291    Undoing,
 1292    Redoing,
 1293    Skipping,
 1294}
 1295
 1296#[derive(Clone, PartialEq, Eq, Hash)]
 1297struct HoveredCursor {
 1298    replica_id: ReplicaId,
 1299    selection_id: usize,
 1300}
 1301
 1302impl Default for SelectionHistoryMode {
 1303    fn default() -> Self {
 1304        Self::Normal
 1305    }
 1306}
 1307
 1308#[derive(Debug)]
 1309/// SelectionEffects controls the side-effects of updating the selection.
 1310///
 1311/// The default behaviour does "what you mostly want":
 1312/// - it pushes to the nav history if the cursor moved by >10 lines
 1313/// - it re-triggers completion requests
 1314/// - it scrolls to fit
 1315///
 1316/// You might want to modify these behaviours. For example when doing a "jump"
 1317/// like go to definition, we always want to add to nav history; but when scrolling
 1318/// in vim mode we never do.
 1319///
 1320/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1321/// move.
 1322#[derive(Clone)]
 1323pub struct SelectionEffects {
 1324    nav_history: Option<bool>,
 1325    completions: bool,
 1326    scroll: Option<Autoscroll>,
 1327}
 1328
 1329impl Default for SelectionEffects {
 1330    fn default() -> Self {
 1331        Self {
 1332            nav_history: None,
 1333            completions: true,
 1334            scroll: Some(Autoscroll::fit()),
 1335        }
 1336    }
 1337}
 1338impl SelectionEffects {
 1339    pub fn scroll(scroll: Autoscroll) -> Self {
 1340        Self {
 1341            scroll: Some(scroll),
 1342            ..Default::default()
 1343        }
 1344    }
 1345
 1346    pub fn no_scroll() -> Self {
 1347        Self {
 1348            scroll: None,
 1349            ..Default::default()
 1350        }
 1351    }
 1352
 1353    pub fn completions(self, completions: bool) -> Self {
 1354        Self {
 1355            completions,
 1356            ..self
 1357        }
 1358    }
 1359
 1360    pub fn nav_history(self, nav_history: bool) -> Self {
 1361        Self {
 1362            nav_history: Some(nav_history),
 1363            ..self
 1364        }
 1365    }
 1366}
 1367
 1368struct DeferredSelectionEffectsState {
 1369    changed: bool,
 1370    effects: SelectionEffects,
 1371    old_cursor_position: Anchor,
 1372    history_entry: SelectionHistoryEntry,
 1373}
 1374
 1375#[derive(Default)]
 1376struct SelectionHistory {
 1377    #[allow(clippy::type_complexity)]
 1378    selections_by_transaction:
 1379        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1380    mode: SelectionHistoryMode,
 1381    undo_stack: VecDeque<SelectionHistoryEntry>,
 1382    redo_stack: VecDeque<SelectionHistoryEntry>,
 1383}
 1384
 1385impl SelectionHistory {
 1386    #[track_caller]
 1387    fn insert_transaction(
 1388        &mut self,
 1389        transaction_id: TransactionId,
 1390        selections: Arc<[Selection<Anchor>]>,
 1391    ) {
 1392        if selections.is_empty() {
 1393            log::error!(
 1394                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1395                std::panic::Location::caller()
 1396            );
 1397            return;
 1398        }
 1399        self.selections_by_transaction
 1400            .insert(transaction_id, (selections, None));
 1401    }
 1402
 1403    #[allow(clippy::type_complexity)]
 1404    fn transaction(
 1405        &self,
 1406        transaction_id: TransactionId,
 1407    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1408        self.selections_by_transaction.get(&transaction_id)
 1409    }
 1410
 1411    #[allow(clippy::type_complexity)]
 1412    fn transaction_mut(
 1413        &mut self,
 1414        transaction_id: TransactionId,
 1415    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1416        self.selections_by_transaction.get_mut(&transaction_id)
 1417    }
 1418
 1419    fn push(&mut self, entry: SelectionHistoryEntry) {
 1420        if !entry.selections.is_empty() {
 1421            match self.mode {
 1422                SelectionHistoryMode::Normal => {
 1423                    self.push_undo(entry);
 1424                    self.redo_stack.clear();
 1425                }
 1426                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1427                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1428                SelectionHistoryMode::Skipping => {}
 1429            }
 1430        }
 1431    }
 1432
 1433    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1434        if self
 1435            .undo_stack
 1436            .back()
 1437            .is_none_or(|e| e.selections != entry.selections)
 1438        {
 1439            self.undo_stack.push_back(entry);
 1440            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1441                self.undo_stack.pop_front();
 1442            }
 1443        }
 1444    }
 1445
 1446    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1447        if self
 1448            .redo_stack
 1449            .back()
 1450            .is_none_or(|e| e.selections != entry.selections)
 1451        {
 1452            self.redo_stack.push_back(entry);
 1453            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1454                self.redo_stack.pop_front();
 1455            }
 1456        }
 1457    }
 1458}
 1459
 1460#[derive(Clone, Copy)]
 1461pub struct RowHighlightOptions {
 1462    pub autoscroll: bool,
 1463    pub include_gutter: bool,
 1464}
 1465
 1466impl Default for RowHighlightOptions {
 1467    fn default() -> Self {
 1468        Self {
 1469            autoscroll: Default::default(),
 1470            include_gutter: true,
 1471        }
 1472    }
 1473}
 1474
 1475struct RowHighlight {
 1476    index: usize,
 1477    range: Range<Anchor>,
 1478    color: Hsla,
 1479    options: RowHighlightOptions,
 1480    type_id: TypeId,
 1481}
 1482
 1483#[derive(Clone, Debug)]
 1484struct AddSelectionsState {
 1485    groups: Vec<AddSelectionsGroup>,
 1486}
 1487
 1488#[derive(Clone, Debug)]
 1489struct AddSelectionsGroup {
 1490    above: bool,
 1491    stack: Vec<usize>,
 1492}
 1493
 1494#[derive(Clone)]
 1495struct SelectNextState {
 1496    query: AhoCorasick,
 1497    wordwise: bool,
 1498    done: bool,
 1499}
 1500
 1501impl std::fmt::Debug for SelectNextState {
 1502    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1503        f.debug_struct(std::any::type_name::<Self>())
 1504            .field("wordwise", &self.wordwise)
 1505            .field("done", &self.done)
 1506            .finish()
 1507    }
 1508}
 1509
 1510#[derive(Debug)]
 1511struct AutocloseRegion {
 1512    selection_id: usize,
 1513    range: Range<Anchor>,
 1514    pair: BracketPair,
 1515}
 1516
 1517#[derive(Debug)]
 1518struct SnippetState {
 1519    ranges: Vec<Vec<Range<Anchor>>>,
 1520    active_index: usize,
 1521    choices: Vec<Option<Vec<String>>>,
 1522}
 1523
 1524#[doc(hidden)]
 1525pub struct RenameState {
 1526    pub range: Range<Anchor>,
 1527    pub old_name: Arc<str>,
 1528    pub editor: Entity<Editor>,
 1529    block_id: CustomBlockId,
 1530}
 1531
 1532struct InvalidationStack<T>(Vec<T>);
 1533
 1534struct RegisteredEditPredictionProvider {
 1535    provider: Arc<dyn EditPredictionProviderHandle>,
 1536    _subscription: Subscription,
 1537}
 1538
 1539#[derive(Debug, PartialEq, Eq)]
 1540pub struct ActiveDiagnosticGroup {
 1541    pub active_range: Range<Anchor>,
 1542    pub active_message: String,
 1543    pub group_id: usize,
 1544    pub blocks: HashSet<CustomBlockId>,
 1545}
 1546
 1547#[derive(Debug, PartialEq, Eq)]
 1548
 1549pub(crate) enum ActiveDiagnostic {
 1550    None,
 1551    All,
 1552    Group(ActiveDiagnosticGroup),
 1553}
 1554
 1555#[derive(Serialize, Deserialize, Clone, Debug)]
 1556pub struct ClipboardSelection {
 1557    /// The number of bytes in this selection.
 1558    pub len: usize,
 1559    /// Whether this was a full-line selection.
 1560    pub is_entire_line: bool,
 1561    /// The indentation of the first line when this content was originally copied.
 1562    pub first_line_indent: u32,
 1563}
 1564
 1565// selections, scroll behavior, was newest selection reversed
 1566type SelectSyntaxNodeHistoryState = (
 1567    Box<[Selection<usize>]>,
 1568    SelectSyntaxNodeScrollBehavior,
 1569    bool,
 1570);
 1571
 1572#[derive(Default)]
 1573struct SelectSyntaxNodeHistory {
 1574    stack: Vec<SelectSyntaxNodeHistoryState>,
 1575    // disable temporarily to allow changing selections without losing the stack
 1576    pub disable_clearing: bool,
 1577}
 1578
 1579impl SelectSyntaxNodeHistory {
 1580    pub fn try_clear(&mut self) {
 1581        if !self.disable_clearing {
 1582            self.stack.clear();
 1583        }
 1584    }
 1585
 1586    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1587        self.stack.push(selection);
 1588    }
 1589
 1590    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1591        self.stack.pop()
 1592    }
 1593}
 1594
 1595enum SelectSyntaxNodeScrollBehavior {
 1596    CursorTop,
 1597    FitSelection,
 1598    CursorBottom,
 1599}
 1600
 1601#[derive(Debug)]
 1602pub(crate) struct NavigationData {
 1603    cursor_anchor: Anchor,
 1604    cursor_position: Point,
 1605    scroll_anchor: ScrollAnchor,
 1606    scroll_top_row: u32,
 1607}
 1608
 1609#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1610pub enum GotoDefinitionKind {
 1611    Symbol,
 1612    Declaration,
 1613    Type,
 1614    Implementation,
 1615}
 1616
 1617pub enum FormatTarget {
 1618    Buffers(HashSet<Entity<Buffer>>),
 1619    Ranges(Vec<Range<MultiBufferPoint>>),
 1620}
 1621
 1622pub(crate) struct FocusedBlock {
 1623    id: BlockId,
 1624    focus_handle: WeakFocusHandle,
 1625}
 1626
 1627#[derive(Clone)]
 1628enum JumpData {
 1629    MultiBufferRow {
 1630        row: MultiBufferRow,
 1631        line_offset_from_top: u32,
 1632    },
 1633    MultiBufferPoint {
 1634        excerpt_id: ExcerptId,
 1635        position: Point,
 1636        anchor: text::Anchor,
 1637        line_offset_from_top: u32,
 1638    },
 1639}
 1640
 1641pub enum MultibufferSelectionMode {
 1642    First,
 1643    All,
 1644}
 1645
 1646#[derive(Clone, Copy, Debug, Default)]
 1647pub struct RewrapOptions {
 1648    pub override_language_settings: bool,
 1649    pub preserve_existing_whitespace: bool,
 1650}
 1651
 1652impl Editor {
 1653    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1654        let buffer = cx.new(|cx| Buffer::local("", cx));
 1655        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1656        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1657    }
 1658
 1659    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1660        let buffer = cx.new(|cx| Buffer::local("", cx));
 1661        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1662        Self::new(EditorMode::full(), buffer, None, window, cx)
 1663    }
 1664
 1665    pub fn auto_height(
 1666        min_lines: usize,
 1667        max_lines: usize,
 1668        window: &mut Window,
 1669        cx: &mut Context<Self>,
 1670    ) -> Self {
 1671        let buffer = cx.new(|cx| Buffer::local("", cx));
 1672        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1673        Self::new(
 1674            EditorMode::AutoHeight {
 1675                min_lines,
 1676                max_lines: Some(max_lines),
 1677            },
 1678            buffer,
 1679            None,
 1680            window,
 1681            cx,
 1682        )
 1683    }
 1684
 1685    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1686    /// The editor grows as tall as needed to fit its content.
 1687    pub fn auto_height_unbounded(
 1688        min_lines: usize,
 1689        window: &mut Window,
 1690        cx: &mut Context<Self>,
 1691    ) -> Self {
 1692        let buffer = cx.new(|cx| Buffer::local("", cx));
 1693        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1694        Self::new(
 1695            EditorMode::AutoHeight {
 1696                min_lines,
 1697                max_lines: None,
 1698            },
 1699            buffer,
 1700            None,
 1701            window,
 1702            cx,
 1703        )
 1704    }
 1705
 1706    pub fn for_buffer(
 1707        buffer: Entity<Buffer>,
 1708        project: Option<Entity<Project>>,
 1709        window: &mut Window,
 1710        cx: &mut Context<Self>,
 1711    ) -> Self {
 1712        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1713        Self::new(EditorMode::full(), buffer, project, window, cx)
 1714    }
 1715
 1716    pub fn for_multibuffer(
 1717        buffer: Entity<MultiBuffer>,
 1718        project: Option<Entity<Project>>,
 1719        window: &mut Window,
 1720        cx: &mut Context<Self>,
 1721    ) -> Self {
 1722        Self::new(EditorMode::full(), buffer, project, window, cx)
 1723    }
 1724
 1725    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1726        let mut clone = Self::new(
 1727            self.mode.clone(),
 1728            self.buffer.clone(),
 1729            self.project.clone(),
 1730            window,
 1731            cx,
 1732        );
 1733        self.display_map.update(cx, |display_map, cx| {
 1734            let snapshot = display_map.snapshot(cx);
 1735            clone.display_map.update(cx, |display_map, cx| {
 1736                display_map.set_state(&snapshot, cx);
 1737            });
 1738        });
 1739        clone.folds_did_change(cx);
 1740        clone.selections.clone_state(&self.selections);
 1741        clone.scroll_manager.clone_state(&self.scroll_manager);
 1742        clone.searchable = self.searchable;
 1743        clone.read_only = self.read_only;
 1744        clone
 1745    }
 1746
 1747    pub fn new(
 1748        mode: EditorMode,
 1749        buffer: Entity<MultiBuffer>,
 1750        project: Option<Entity<Project>>,
 1751        window: &mut Window,
 1752        cx: &mut Context<Self>,
 1753    ) -> Self {
 1754        Editor::new_internal(mode, buffer, project, None, window, cx)
 1755    }
 1756
 1757    fn new_internal(
 1758        mode: EditorMode,
 1759        multi_buffer: Entity<MultiBuffer>,
 1760        project: Option<Entity<Project>>,
 1761        display_map: Option<Entity<DisplayMap>>,
 1762        window: &mut Window,
 1763        cx: &mut Context<Self>,
 1764    ) -> Self {
 1765        debug_assert!(
 1766            display_map.is_none() || mode.is_minimap(),
 1767            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1768        );
 1769
 1770        let full_mode = mode.is_full();
 1771        let is_minimap = mode.is_minimap();
 1772        let diagnostics_max_severity = if full_mode {
 1773            EditorSettings::get_global(cx)
 1774                .diagnostics_max_severity
 1775                .unwrap_or(DiagnosticSeverity::Hint)
 1776        } else {
 1777            DiagnosticSeverity::Off
 1778        };
 1779        let style = window.text_style();
 1780        let font_size = style.font_size.to_pixels(window.rem_size());
 1781        let editor = cx.entity().downgrade();
 1782        let fold_placeholder = FoldPlaceholder {
 1783            constrain_width: false,
 1784            render: Arc::new(move |fold_id, fold_range, cx| {
 1785                let editor = editor.clone();
 1786                div()
 1787                    .id(fold_id)
 1788                    .bg(cx.theme().colors().ghost_element_background)
 1789                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1790                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1791                    .rounded_xs()
 1792                    .size_full()
 1793                    .cursor_pointer()
 1794                    .child("")
 1795                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1796                    .on_click(move |_, _window, cx| {
 1797                        editor
 1798                            .update(cx, |editor, cx| {
 1799                                editor.unfold_ranges(
 1800                                    &[fold_range.start..fold_range.end],
 1801                                    true,
 1802                                    false,
 1803                                    cx,
 1804                                );
 1805                                cx.stop_propagation();
 1806                            })
 1807                            .ok();
 1808                    })
 1809                    .into_any()
 1810            }),
 1811            merge_adjacent: true,
 1812            ..FoldPlaceholder::default()
 1813        };
 1814        let display_map = display_map.unwrap_or_else(|| {
 1815            cx.new(|cx| {
 1816                DisplayMap::new(
 1817                    multi_buffer.clone(),
 1818                    style.font(),
 1819                    font_size,
 1820                    None,
 1821                    FILE_HEADER_HEIGHT,
 1822                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1823                    fold_placeholder,
 1824                    diagnostics_max_severity,
 1825                    cx,
 1826                )
 1827            })
 1828        });
 1829
 1830        let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
 1831
 1832        let blink_manager = cx.new(|cx| {
 1833            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1834            if is_minimap {
 1835                blink_manager.disable(cx);
 1836            }
 1837            blink_manager
 1838        });
 1839
 1840        let soft_wrap_mode_override =
 1841            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1842
 1843        let mut project_subscriptions = Vec::new();
 1844        if full_mode && let Some(project) = project.as_ref() {
 1845            project_subscriptions.push(cx.subscribe_in(
 1846                project,
 1847                window,
 1848                |editor, _, event, window, cx| match event {
 1849                    project::Event::RefreshCodeLens => {
 1850                        // we always query lens with actions, without storing them, always refreshing them
 1851                    }
 1852                    project::Event::RefreshInlayHints {
 1853                        server_id,
 1854                        request_id,
 1855                    } => {
 1856                        editor.refresh_inlay_hints(
 1857                            InlayHintRefreshReason::RefreshRequested {
 1858                                server_id: *server_id,
 1859                                request_id: *request_id,
 1860                            },
 1861                            cx,
 1862                        );
 1863                    }
 1864                    project::Event::LanguageServerRemoved(..) => {
 1865                        if editor.tasks_update_task.is_none() {
 1866                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1867                        }
 1868                        editor.registered_buffers.clear();
 1869                        editor.register_visible_buffers(cx);
 1870                    }
 1871                    project::Event::LanguageServerAdded(..) => {
 1872                        if editor.tasks_update_task.is_none() {
 1873                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1874                        }
 1875                    }
 1876                    project::Event::SnippetEdit(id, snippet_edits) => {
 1877                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1878                            let focus_handle = editor.focus_handle(cx);
 1879                            if focus_handle.is_focused(window) {
 1880                                let snapshot = buffer.read(cx).snapshot();
 1881                                for (range, snippet) in snippet_edits {
 1882                                    let editor_range =
 1883                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1884                                    editor
 1885                                        .insert_snippet(
 1886                                            &[editor_range],
 1887                                            snippet.clone(),
 1888                                            window,
 1889                                            cx,
 1890                                        )
 1891                                        .ok();
 1892                                }
 1893                            }
 1894                        }
 1895                    }
 1896                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1897                        let buffer_id = *buffer_id;
 1898                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1899                            editor.register_buffer(buffer_id, cx);
 1900                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1901                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1902                            refresh_linked_ranges(editor, window, cx);
 1903                            editor.refresh_code_actions(window, cx);
 1904                            editor.refresh_document_highlights(cx);
 1905                        }
 1906                    }
 1907
 1908                    project::Event::EntryRenamed(transaction) => {
 1909                        let Some(workspace) = editor.workspace() else {
 1910                            return;
 1911                        };
 1912                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1913                        else {
 1914                            return;
 1915                        };
 1916                        if active_editor.entity_id() == cx.entity_id() {
 1917                            let edited_buffers_already_open = {
 1918                                let other_editors: Vec<Entity<Editor>> = workspace
 1919                                    .read(cx)
 1920                                    .panes()
 1921                                    .iter()
 1922                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1923                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1924                                    .collect();
 1925
 1926                                transaction.0.keys().all(|buffer| {
 1927                                    other_editors.iter().any(|editor| {
 1928                                        let multi_buffer = editor.read(cx).buffer();
 1929                                        multi_buffer.read(cx).is_singleton()
 1930                                            && multi_buffer.read(cx).as_singleton().map_or(
 1931                                                false,
 1932                                                |singleton| {
 1933                                                    singleton.entity_id() == buffer.entity_id()
 1934                                                },
 1935                                            )
 1936                                    })
 1937                                })
 1938                            };
 1939
 1940                            if !edited_buffers_already_open {
 1941                                let workspace = workspace.downgrade();
 1942                                let transaction = transaction.clone();
 1943                                cx.defer_in(window, move |_, window, cx| {
 1944                                    cx.spawn_in(window, async move |editor, cx| {
 1945                                        Self::open_project_transaction(
 1946                                            &editor,
 1947                                            workspace,
 1948                                            transaction,
 1949                                            "Rename".to_string(),
 1950                                            cx,
 1951                                        )
 1952                                        .await
 1953                                        .ok()
 1954                                    })
 1955                                    .detach();
 1956                                });
 1957                            }
 1958                        }
 1959                    }
 1960
 1961                    _ => {}
 1962                },
 1963            ));
 1964            if let Some(task_inventory) = project
 1965                .read(cx)
 1966                .task_store()
 1967                .read(cx)
 1968                .task_inventory()
 1969                .cloned()
 1970            {
 1971                project_subscriptions.push(cx.observe_in(
 1972                    &task_inventory,
 1973                    window,
 1974                    |editor, _, window, cx| {
 1975                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1976                    },
 1977                ));
 1978            };
 1979
 1980            project_subscriptions.push(cx.subscribe_in(
 1981                &project.read(cx).breakpoint_store(),
 1982                window,
 1983                |editor, _, event, window, cx| match event {
 1984                    BreakpointStoreEvent::ClearDebugLines => {
 1985                        editor.clear_row_highlights::<ActiveDebugLine>();
 1986                        editor.refresh_inline_values(cx);
 1987                    }
 1988                    BreakpointStoreEvent::SetDebugLine => {
 1989                        if editor.go_to_active_debug_line(window, cx) {
 1990                            cx.stop_propagation();
 1991                        }
 1992
 1993                        editor.refresh_inline_values(cx);
 1994                    }
 1995                    _ => {}
 1996                },
 1997            ));
 1998            let git_store = project.read(cx).git_store().clone();
 1999            let project = project.clone();
 2000            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2001                if let GitStoreEvent::RepositoryAdded = event {
 2002                    this.load_diff_task = Some(
 2003                        update_uncommitted_diff_for_buffer(
 2004                            cx.entity(),
 2005                            &project,
 2006                            this.buffer.read(cx).all_buffers(),
 2007                            this.buffer.clone(),
 2008                            cx,
 2009                        )
 2010                        .shared(),
 2011                    );
 2012                }
 2013            }));
 2014        }
 2015
 2016        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2017
 2018        let inlay_hint_settings =
 2019            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2020        let focus_handle = cx.focus_handle();
 2021        if !is_minimap {
 2022            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2023                .detach();
 2024            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2025                .detach();
 2026            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2027                .detach();
 2028            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2029                .detach();
 2030            cx.observe_pending_input(window, Self::observe_pending_input)
 2031                .detach();
 2032        }
 2033
 2034        let show_indent_guides =
 2035            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2036                Some(false)
 2037            } else {
 2038                None
 2039            };
 2040
 2041        let breakpoint_store = match (&mode, project.as_ref()) {
 2042            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2043            _ => None,
 2044        };
 2045
 2046        let mut code_action_providers = Vec::new();
 2047        let mut load_uncommitted_diff = None;
 2048        if let Some(project) = project.clone() {
 2049            load_uncommitted_diff = Some(
 2050                update_uncommitted_diff_for_buffer(
 2051                    cx.entity(),
 2052                    &project,
 2053                    multi_buffer.read(cx).all_buffers(),
 2054                    multi_buffer.clone(),
 2055                    cx,
 2056                )
 2057                .shared(),
 2058            );
 2059            code_action_providers.push(Rc::new(project) as Rc<_>);
 2060        }
 2061
 2062        let mut editor = Self {
 2063            focus_handle,
 2064            show_cursor_when_unfocused: false,
 2065            last_focused_descendant: None,
 2066            buffer: multi_buffer.clone(),
 2067            display_map: display_map.clone(),
 2068            placeholder_display_map: None,
 2069            selections,
 2070            scroll_manager: ScrollManager::new(cx),
 2071            columnar_selection_state: None,
 2072            add_selections_state: None,
 2073            select_next_state: None,
 2074            select_prev_state: None,
 2075            selection_history: SelectionHistory::default(),
 2076            defer_selection_effects: false,
 2077            deferred_selection_effects_state: None,
 2078            autoclose_regions: Vec::new(),
 2079            snippet_stack: InvalidationStack::default(),
 2080            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2081            ime_transaction: None,
 2082            active_diagnostics: ActiveDiagnostic::None,
 2083            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2084            inline_diagnostics_update: Task::ready(()),
 2085            inline_diagnostics: Vec::new(),
 2086            soft_wrap_mode_override,
 2087            diagnostics_max_severity,
 2088            hard_wrap: None,
 2089            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2090            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2091            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2092            project,
 2093            blink_manager: blink_manager.clone(),
 2094            show_local_selections: true,
 2095            show_scrollbars: ScrollbarAxes {
 2096                horizontal: full_mode,
 2097                vertical: full_mode,
 2098            },
 2099            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2100            offset_content: !matches!(mode, EditorMode::SingleLine),
 2101            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2102            show_gutter: full_mode,
 2103            show_line_numbers: (!full_mode).then_some(false),
 2104            use_relative_line_numbers: None,
 2105            disable_expand_excerpt_buttons: !full_mode,
 2106            show_git_diff_gutter: None,
 2107            show_code_actions: None,
 2108            show_runnables: None,
 2109            show_breakpoints: None,
 2110            show_wrap_guides: None,
 2111            show_indent_guides,
 2112            highlight_order: 0,
 2113            highlighted_rows: HashMap::default(),
 2114            background_highlights: HashMap::default(),
 2115            gutter_highlights: HashMap::default(),
 2116            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2117            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2118            nav_history: None,
 2119            context_menu: RefCell::new(None),
 2120            context_menu_options: None,
 2121            mouse_context_menu: None,
 2122            completion_tasks: Vec::new(),
 2123            inline_blame_popover: None,
 2124            inline_blame_popover_show_task: None,
 2125            signature_help_state: SignatureHelpState::default(),
 2126            auto_signature_help: None,
 2127            find_all_references_task_sources: Vec::new(),
 2128            next_completion_id: 0,
 2129            next_inlay_id: 0,
 2130            code_action_providers,
 2131            available_code_actions: None,
 2132            code_actions_task: None,
 2133            quick_selection_highlight_task: None,
 2134            debounced_selection_highlight_task: None,
 2135            document_highlights_task: None,
 2136            linked_editing_range_task: None,
 2137            pending_rename: None,
 2138            searchable: !is_minimap,
 2139            cursor_shape: EditorSettings::get_global(cx)
 2140                .cursor_shape
 2141                .unwrap_or_default(),
 2142            current_line_highlight: None,
 2143            autoindent_mode: Some(AutoindentMode::EachLine),
 2144
 2145            workspace: None,
 2146            input_enabled: !is_minimap,
 2147            use_modal_editing: full_mode,
 2148            read_only: is_minimap,
 2149            use_autoclose: true,
 2150            use_auto_surround: true,
 2151            auto_replace_emoji_shortcode: false,
 2152            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2153            leader_id: None,
 2154            remote_id: None,
 2155            hover_state: HoverState::default(),
 2156            pending_mouse_down: None,
 2157            hovered_link_state: None,
 2158            edit_prediction_provider: None,
 2159            active_edit_prediction: None,
 2160            stale_edit_prediction_in_menu: None,
 2161            edit_prediction_preview: EditPredictionPreview::Inactive {
 2162                released_too_fast: false,
 2163            },
 2164            inline_diagnostics_enabled: full_mode,
 2165            diagnostics_enabled: full_mode,
 2166            word_completions_enabled: full_mode,
 2167            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2168            gutter_hovered: false,
 2169            pixel_position_of_newest_cursor: None,
 2170            last_bounds: None,
 2171            last_position_map: None,
 2172            expect_bounds_change: None,
 2173            gutter_dimensions: GutterDimensions::default(),
 2174            style: None,
 2175            show_cursor_names: false,
 2176            hovered_cursors: HashMap::default(),
 2177            next_editor_action_id: EditorActionId::default(),
 2178            editor_actions: Rc::default(),
 2179            edit_predictions_hidden_for_vim_mode: false,
 2180            show_edit_predictions_override: None,
 2181            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2182            edit_prediction_settings: EditPredictionSettings::Disabled,
 2183            edit_prediction_indent_conflict: false,
 2184            edit_prediction_requires_modifier_in_indent_conflict: true,
 2185            custom_context_menu: None,
 2186            show_git_blame_gutter: false,
 2187            show_git_blame_inline: false,
 2188            show_selection_menu: None,
 2189            show_git_blame_inline_delay_task: None,
 2190            git_blame_inline_enabled: full_mode
 2191                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2192            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2193            serialize_dirty_buffers: !is_minimap
 2194                && ProjectSettings::get_global(cx)
 2195                    .session
 2196                    .restore_unsaved_buffers,
 2197            blame: None,
 2198            blame_subscription: None,
 2199            tasks: BTreeMap::default(),
 2200
 2201            breakpoint_store,
 2202            gutter_breakpoint_indicator: (None, None),
 2203            hovered_diff_hunk_row: None,
 2204            _subscriptions: (!is_minimap)
 2205                .then(|| {
 2206                    vec![
 2207                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2208                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2209                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2210                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2211                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2212                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2213                        cx.observe_window_activation(window, |editor, window, cx| {
 2214                            let active = window.is_window_active();
 2215                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2216                                if active {
 2217                                    blink_manager.enable(cx);
 2218                                } else {
 2219                                    blink_manager.disable(cx);
 2220                                }
 2221                            });
 2222                            if active {
 2223                                editor.show_mouse_cursor(cx);
 2224                            }
 2225                        }),
 2226                    ]
 2227                })
 2228                .unwrap_or_default(),
 2229            tasks_update_task: None,
 2230            pull_diagnostics_task: Task::ready(()),
 2231            colors: None,
 2232            refresh_colors_task: Task::ready(()),
 2233            inlay_hints: None,
 2234            next_color_inlay_id: 0,
 2235            post_scroll_update: Task::ready(()),
 2236            linked_edit_ranges: Default::default(),
 2237            in_project_search: false,
 2238            previous_search_ranges: None,
 2239            breadcrumb_header: None,
 2240            focused_block: None,
 2241            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2242            addons: HashMap::default(),
 2243            registered_buffers: HashMap::default(),
 2244            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2245            selection_mark_mode: false,
 2246            toggle_fold_multiple_buffers: Task::ready(()),
 2247            serialize_selections: Task::ready(()),
 2248            serialize_folds: Task::ready(()),
 2249            text_style_refinement: None,
 2250            load_diff_task: load_uncommitted_diff,
 2251            temporary_diff_override: false,
 2252            mouse_cursor_hidden: false,
 2253            minimap: None,
 2254            hide_mouse_mode: EditorSettings::get_global(cx)
 2255                .hide_mouse
 2256                .unwrap_or_default(),
 2257            change_list: ChangeList::new(),
 2258            mode,
 2259            selection_drag_state: SelectionDragState::None,
 2260            folding_newlines: Task::ready(()),
 2261            lookup_key: None,
 2262        };
 2263
 2264        if is_minimap {
 2265            return editor;
 2266        }
 2267
 2268        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2269            editor
 2270                ._subscriptions
 2271                .push(cx.observe(breakpoints, |_, _, cx| {
 2272                    cx.notify();
 2273                }));
 2274        }
 2275        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2276        editor._subscriptions.extend(project_subscriptions);
 2277
 2278        editor._subscriptions.push(cx.subscribe_in(
 2279            &cx.entity(),
 2280            window,
 2281            |editor, _, e: &EditorEvent, window, cx| match e {
 2282                EditorEvent::ScrollPositionChanged { local, .. } => {
 2283                    if *local {
 2284                        let new_anchor = editor.scroll_manager.anchor();
 2285                        let snapshot = editor.snapshot(window, cx);
 2286                        editor.update_restoration_data(cx, move |data| {
 2287                            data.scroll_position = (
 2288                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2289                                new_anchor.offset,
 2290                            );
 2291                        });
 2292                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2293                        editor.inline_blame_popover.take();
 2294                    }
 2295                }
 2296                EditorEvent::Edited { .. } => {
 2297                    if vim_flavor(cx).is_none() {
 2298                        let display_map = editor.display_snapshot(cx);
 2299                        let selections = editor.selections.all_adjusted_display(&display_map);
 2300                        let pop_state = editor
 2301                            .change_list
 2302                            .last()
 2303                            .map(|previous| {
 2304                                previous.len() == selections.len()
 2305                                    && previous.iter().enumerate().all(|(ix, p)| {
 2306                                        p.to_display_point(&display_map).row()
 2307                                            == selections[ix].head().row()
 2308                                    })
 2309                            })
 2310                            .unwrap_or(false);
 2311                        let new_positions = selections
 2312                            .into_iter()
 2313                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2314                            .collect();
 2315                        editor
 2316                            .change_list
 2317                            .push_to_change_list(pop_state, new_positions);
 2318                    }
 2319                }
 2320                _ => (),
 2321            },
 2322        ));
 2323
 2324        if let Some(dap_store) = editor
 2325            .project
 2326            .as_ref()
 2327            .map(|project| project.read(cx).dap_store())
 2328        {
 2329            let weak_editor = cx.weak_entity();
 2330
 2331            editor
 2332                ._subscriptions
 2333                .push(
 2334                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2335                        let session_entity = cx.entity();
 2336                        weak_editor
 2337                            .update(cx, |editor, cx| {
 2338                                editor._subscriptions.push(
 2339                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2340                                );
 2341                            })
 2342                            .ok();
 2343                    }),
 2344                );
 2345
 2346            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2347                editor
 2348                    ._subscriptions
 2349                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2350            }
 2351        }
 2352
 2353        // skip adding the initial selection to selection history
 2354        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2355        editor.end_selection(window, cx);
 2356        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2357
 2358        editor.scroll_manager.show_scrollbars(window, cx);
 2359        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2360
 2361        if full_mode {
 2362            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2363            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2364
 2365            if editor.git_blame_inline_enabled {
 2366                editor.start_git_blame_inline(false, window, cx);
 2367            }
 2368
 2369            editor.go_to_active_debug_line(window, cx);
 2370
 2371            editor.minimap =
 2372                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2373            editor.colors = Some(LspColorData::new(cx));
 2374            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2375
 2376            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2377                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2378            }
 2379            editor.update_lsp_data(None, window, cx);
 2380            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2381        }
 2382
 2383        editor
 2384    }
 2385
 2386    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2387        self.selections.display_map(cx)
 2388    }
 2389
 2390    pub fn deploy_mouse_context_menu(
 2391        &mut self,
 2392        position: gpui::Point<Pixels>,
 2393        context_menu: Entity<ContextMenu>,
 2394        window: &mut Window,
 2395        cx: &mut Context<Self>,
 2396    ) {
 2397        self.mouse_context_menu = Some(MouseContextMenu::new(
 2398            self,
 2399            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2400            context_menu,
 2401            window,
 2402            cx,
 2403        ));
 2404    }
 2405
 2406    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2407        self.mouse_context_menu
 2408            .as_ref()
 2409            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2410    }
 2411
 2412    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2413        if self
 2414            .selections
 2415            .pending_anchor()
 2416            .is_some_and(|pending_selection| {
 2417                let snapshot = self.buffer().read(cx).snapshot(cx);
 2418                pending_selection.range().includes(range, &snapshot)
 2419            })
 2420        {
 2421            return true;
 2422        }
 2423
 2424        self.selections
 2425            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2426            .into_iter()
 2427            .any(|selection| {
 2428                // This is needed to cover a corner case, if we just check for an existing
 2429                // selection in the fold range, having a cursor at the start of the fold
 2430                // marks it as selected. Non-empty selections don't cause this.
 2431                let length = selection.end - selection.start;
 2432                length > 0
 2433            })
 2434    }
 2435
 2436    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2437        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2438    }
 2439
 2440    fn key_context_internal(
 2441        &self,
 2442        has_active_edit_prediction: bool,
 2443        window: &mut Window,
 2444        cx: &mut App,
 2445    ) -> KeyContext {
 2446        let mut key_context = KeyContext::new_with_defaults();
 2447        key_context.add("Editor");
 2448        let mode = match self.mode {
 2449            EditorMode::SingleLine => "single_line",
 2450            EditorMode::AutoHeight { .. } => "auto_height",
 2451            EditorMode::Minimap { .. } => "minimap",
 2452            EditorMode::Full { .. } => "full",
 2453        };
 2454
 2455        if EditorSettings::jupyter_enabled(cx) {
 2456            key_context.add("jupyter");
 2457        }
 2458
 2459        key_context.set("mode", mode);
 2460        if self.pending_rename.is_some() {
 2461            key_context.add("renaming");
 2462        }
 2463
 2464        if !self.snippet_stack.is_empty() {
 2465            key_context.add("in_snippet");
 2466        }
 2467
 2468        match self.context_menu.borrow().as_ref() {
 2469            Some(CodeContextMenu::Completions(menu)) => {
 2470                if menu.visible() {
 2471                    key_context.add("menu");
 2472                    key_context.add("showing_completions");
 2473                }
 2474            }
 2475            Some(CodeContextMenu::CodeActions(menu)) => {
 2476                if menu.visible() {
 2477                    key_context.add("menu");
 2478                    key_context.add("showing_code_actions")
 2479                }
 2480            }
 2481            None => {}
 2482        }
 2483
 2484        if self.signature_help_state.has_multiple_signatures() {
 2485            key_context.add("showing_signature_help");
 2486        }
 2487
 2488        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2489        if !self.focus_handle(cx).contains_focused(window, cx)
 2490            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2491        {
 2492            for addon in self.addons.values() {
 2493                addon.extend_key_context(&mut key_context, cx)
 2494            }
 2495        }
 2496
 2497        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2498            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2499                Some(
 2500                    file.full_path(cx)
 2501                        .extension()?
 2502                        .to_string_lossy()
 2503                        .into_owned(),
 2504                )
 2505            }) {
 2506                key_context.set("extension", extension);
 2507            }
 2508        } else {
 2509            key_context.add("multibuffer");
 2510        }
 2511
 2512        if has_active_edit_prediction {
 2513            if self.edit_prediction_in_conflict() {
 2514                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2515            } else {
 2516                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2517                key_context.add("copilot_suggestion");
 2518            }
 2519        }
 2520
 2521        if self.selection_mark_mode {
 2522            key_context.add("selection_mode");
 2523        }
 2524
 2525        let disjoint = self.selections.disjoint_anchors();
 2526        let snapshot = self.snapshot(window, cx);
 2527        let snapshot = snapshot.buffer_snapshot();
 2528        if self.mode == EditorMode::SingleLine
 2529            && let [selection] = disjoint
 2530            && selection.start == selection.end
 2531            && selection.end.to_offset(snapshot) == snapshot.len()
 2532        {
 2533            key_context.add("end_of_input");
 2534        }
 2535
 2536        key_context
 2537    }
 2538
 2539    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2540        self.last_bounds.as_ref()
 2541    }
 2542
 2543    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2544        if self.mouse_cursor_hidden {
 2545            self.mouse_cursor_hidden = false;
 2546            cx.notify();
 2547        }
 2548    }
 2549
 2550    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2551        let hide_mouse_cursor = match origin {
 2552            HideMouseCursorOrigin::TypingAction => {
 2553                matches!(
 2554                    self.hide_mouse_mode,
 2555                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2556                )
 2557            }
 2558            HideMouseCursorOrigin::MovementAction => {
 2559                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2560            }
 2561        };
 2562        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2563            self.mouse_cursor_hidden = hide_mouse_cursor;
 2564            cx.notify();
 2565        }
 2566    }
 2567
 2568    pub fn edit_prediction_in_conflict(&self) -> bool {
 2569        if !self.show_edit_predictions_in_menu() {
 2570            return false;
 2571        }
 2572
 2573        let showing_completions = self
 2574            .context_menu
 2575            .borrow()
 2576            .as_ref()
 2577            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2578
 2579        showing_completions
 2580            || self.edit_prediction_requires_modifier()
 2581            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2582            // bindings to insert tab characters.
 2583            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2584    }
 2585
 2586    pub fn accept_edit_prediction_keybind(
 2587        &self,
 2588        accept_partial: bool,
 2589        window: &mut Window,
 2590        cx: &mut App,
 2591    ) -> AcceptEditPredictionBinding {
 2592        let key_context = self.key_context_internal(true, window, cx);
 2593        let in_conflict = self.edit_prediction_in_conflict();
 2594
 2595        let bindings = if accept_partial {
 2596            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2597        } else {
 2598            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2599        };
 2600
 2601        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2602        // just the first one.
 2603        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2604            !in_conflict
 2605                || binding
 2606                    .keystrokes()
 2607                    .first()
 2608                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2609        }))
 2610    }
 2611
 2612    pub fn new_file(
 2613        workspace: &mut Workspace,
 2614        _: &workspace::NewFile,
 2615        window: &mut Window,
 2616        cx: &mut Context<Workspace>,
 2617    ) {
 2618        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2619            "Failed to create buffer",
 2620            window,
 2621            cx,
 2622            |e, _, _| match e.error_code() {
 2623                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2624                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2625                e.error_tag("required").unwrap_or("the latest version")
 2626            )),
 2627                _ => None,
 2628            },
 2629        );
 2630    }
 2631
 2632    pub fn new_in_workspace(
 2633        workspace: &mut Workspace,
 2634        window: &mut Window,
 2635        cx: &mut Context<Workspace>,
 2636    ) -> Task<Result<Entity<Editor>>> {
 2637        let project = workspace.project().clone();
 2638        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2639
 2640        cx.spawn_in(window, async move |workspace, cx| {
 2641            let buffer = create.await?;
 2642            workspace.update_in(cx, |workspace, window, cx| {
 2643                let editor =
 2644                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2645                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2646                editor
 2647            })
 2648        })
 2649    }
 2650
 2651    fn new_file_vertical(
 2652        workspace: &mut Workspace,
 2653        _: &workspace::NewFileSplitVertical,
 2654        window: &mut Window,
 2655        cx: &mut Context<Workspace>,
 2656    ) {
 2657        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2658    }
 2659
 2660    fn new_file_horizontal(
 2661        workspace: &mut Workspace,
 2662        _: &workspace::NewFileSplitHorizontal,
 2663        window: &mut Window,
 2664        cx: &mut Context<Workspace>,
 2665    ) {
 2666        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2667    }
 2668
 2669    fn new_file_split(
 2670        workspace: &mut Workspace,
 2671        action: &workspace::NewFileSplit,
 2672        window: &mut Window,
 2673        cx: &mut Context<Workspace>,
 2674    ) {
 2675        Self::new_file_in_direction(workspace, action.0, window, cx)
 2676    }
 2677
 2678    fn new_file_in_direction(
 2679        workspace: &mut Workspace,
 2680        direction: SplitDirection,
 2681        window: &mut Window,
 2682        cx: &mut Context<Workspace>,
 2683    ) {
 2684        let project = workspace.project().clone();
 2685        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2686
 2687        cx.spawn_in(window, async move |workspace, cx| {
 2688            let buffer = create.await?;
 2689            workspace.update_in(cx, move |workspace, window, cx| {
 2690                workspace.split_item(
 2691                    direction,
 2692                    Box::new(
 2693                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2694                    ),
 2695                    window,
 2696                    cx,
 2697                )
 2698            })?;
 2699            anyhow::Ok(())
 2700        })
 2701        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2702            match e.error_code() {
 2703                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2704                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2705                e.error_tag("required").unwrap_or("the latest version")
 2706            )),
 2707                _ => None,
 2708            }
 2709        });
 2710    }
 2711
 2712    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2713        self.leader_id
 2714    }
 2715
 2716    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2717        &self.buffer
 2718    }
 2719
 2720    pub fn project(&self) -> Option<&Entity<Project>> {
 2721        self.project.as_ref()
 2722    }
 2723
 2724    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2725        self.workspace.as_ref()?.0.upgrade()
 2726    }
 2727
 2728    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2729        self.buffer().read(cx).title(cx)
 2730    }
 2731
 2732    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2733        let git_blame_gutter_max_author_length = self
 2734            .render_git_blame_gutter(cx)
 2735            .then(|| {
 2736                if let Some(blame) = self.blame.as_ref() {
 2737                    let max_author_length =
 2738                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2739                    Some(max_author_length)
 2740                } else {
 2741                    None
 2742                }
 2743            })
 2744            .flatten();
 2745
 2746        EditorSnapshot {
 2747            mode: self.mode.clone(),
 2748            show_gutter: self.show_gutter,
 2749            show_line_numbers: self.show_line_numbers,
 2750            show_git_diff_gutter: self.show_git_diff_gutter,
 2751            show_code_actions: self.show_code_actions,
 2752            show_runnables: self.show_runnables,
 2753            show_breakpoints: self.show_breakpoints,
 2754            git_blame_gutter_max_author_length,
 2755            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2756            placeholder_display_snapshot: self
 2757                .placeholder_display_map
 2758                .as_ref()
 2759                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2760            scroll_anchor: self.scroll_manager.anchor(),
 2761            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2762            is_focused: self.focus_handle.is_focused(window),
 2763            current_line_highlight: self
 2764                .current_line_highlight
 2765                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2766            gutter_hovered: self.gutter_hovered,
 2767        }
 2768    }
 2769
 2770    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2771        self.buffer.read(cx).language_at(point, cx)
 2772    }
 2773
 2774    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2775        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2776    }
 2777
 2778    pub fn active_excerpt(
 2779        &self,
 2780        cx: &App,
 2781    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2782        self.buffer
 2783            .read(cx)
 2784            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2785    }
 2786
 2787    pub fn mode(&self) -> &EditorMode {
 2788        &self.mode
 2789    }
 2790
 2791    pub fn set_mode(&mut self, mode: EditorMode) {
 2792        self.mode = mode;
 2793    }
 2794
 2795    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2796        self.collaboration_hub.as_deref()
 2797    }
 2798
 2799    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2800        self.collaboration_hub = Some(hub);
 2801    }
 2802
 2803    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2804        self.in_project_search = in_project_search;
 2805    }
 2806
 2807    pub fn set_custom_context_menu(
 2808        &mut self,
 2809        f: impl 'static
 2810        + Fn(
 2811            &mut Self,
 2812            DisplayPoint,
 2813            &mut Window,
 2814            &mut Context<Self>,
 2815        ) -> Option<Entity<ui::ContextMenu>>,
 2816    ) {
 2817        self.custom_context_menu = Some(Box::new(f))
 2818    }
 2819
 2820    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2821        self.completion_provider = provider;
 2822    }
 2823
 2824    #[cfg(any(test, feature = "test-support"))]
 2825    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2826        self.completion_provider.clone()
 2827    }
 2828
 2829    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2830        self.semantics_provider.clone()
 2831    }
 2832
 2833    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2834        self.semantics_provider = provider;
 2835    }
 2836
 2837    pub fn set_edit_prediction_provider<T>(
 2838        &mut self,
 2839        provider: Option<Entity<T>>,
 2840        window: &mut Window,
 2841        cx: &mut Context<Self>,
 2842    ) where
 2843        T: EditPredictionProvider,
 2844    {
 2845        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2846            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2847                if this.focus_handle.is_focused(window) {
 2848                    this.update_visible_edit_prediction(window, cx);
 2849                }
 2850            }),
 2851            provider: Arc::new(provider),
 2852        });
 2853        self.update_edit_prediction_settings(cx);
 2854        self.refresh_edit_prediction(false, false, window, cx);
 2855    }
 2856
 2857    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2858        self.placeholder_display_map
 2859            .as_ref()
 2860            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2861    }
 2862
 2863    pub fn set_placeholder_text(
 2864        &mut self,
 2865        placeholder_text: &str,
 2866        window: &mut Window,
 2867        cx: &mut Context<Self>,
 2868    ) {
 2869        let multibuffer = cx
 2870            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2871
 2872        let style = window.text_style();
 2873
 2874        self.placeholder_display_map = Some(cx.new(|cx| {
 2875            DisplayMap::new(
 2876                multibuffer,
 2877                style.font(),
 2878                style.font_size.to_pixels(window.rem_size()),
 2879                None,
 2880                FILE_HEADER_HEIGHT,
 2881                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2882                Default::default(),
 2883                DiagnosticSeverity::Off,
 2884                cx,
 2885            )
 2886        }));
 2887        cx.notify();
 2888    }
 2889
 2890    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2891        self.cursor_shape = cursor_shape;
 2892
 2893        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2894        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2895
 2896        cx.notify();
 2897    }
 2898
 2899    pub fn set_current_line_highlight(
 2900        &mut self,
 2901        current_line_highlight: Option<CurrentLineHighlight>,
 2902    ) {
 2903        self.current_line_highlight = current_line_highlight;
 2904    }
 2905
 2906    pub fn range_for_match<T: std::marker::Copy>(
 2907        &self,
 2908        range: &Range<T>,
 2909        collapse: bool,
 2910    ) -> Range<T> {
 2911        if collapse {
 2912            return range.start..range.start;
 2913        }
 2914        range.clone()
 2915    }
 2916
 2917    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2918        if self.display_map.read(cx).clip_at_line_ends != clip {
 2919            self.display_map
 2920                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2921        }
 2922    }
 2923
 2924    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2925        self.input_enabled = input_enabled;
 2926    }
 2927
 2928    pub fn set_edit_predictions_hidden_for_vim_mode(
 2929        &mut self,
 2930        hidden: bool,
 2931        window: &mut Window,
 2932        cx: &mut Context<Self>,
 2933    ) {
 2934        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2935            self.edit_predictions_hidden_for_vim_mode = hidden;
 2936            if hidden {
 2937                self.update_visible_edit_prediction(window, cx);
 2938            } else {
 2939                self.refresh_edit_prediction(true, false, window, cx);
 2940            }
 2941        }
 2942    }
 2943
 2944    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2945        self.menu_edit_predictions_policy = value;
 2946    }
 2947
 2948    pub fn set_autoindent(&mut self, autoindent: bool) {
 2949        if autoindent {
 2950            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2951        } else {
 2952            self.autoindent_mode = None;
 2953        }
 2954    }
 2955
 2956    pub fn read_only(&self, cx: &App) -> bool {
 2957        self.read_only || self.buffer.read(cx).read_only()
 2958    }
 2959
 2960    pub fn set_read_only(&mut self, read_only: bool) {
 2961        self.read_only = read_only;
 2962    }
 2963
 2964    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2965        self.use_autoclose = autoclose;
 2966    }
 2967
 2968    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2969        self.use_auto_surround = auto_surround;
 2970    }
 2971
 2972    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2973        self.auto_replace_emoji_shortcode = auto_replace;
 2974    }
 2975
 2976    pub fn toggle_edit_predictions(
 2977        &mut self,
 2978        _: &ToggleEditPrediction,
 2979        window: &mut Window,
 2980        cx: &mut Context<Self>,
 2981    ) {
 2982        if self.show_edit_predictions_override.is_some() {
 2983            self.set_show_edit_predictions(None, window, cx);
 2984        } else {
 2985            let show_edit_predictions = !self.edit_predictions_enabled();
 2986            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2987        }
 2988    }
 2989
 2990    pub fn set_show_edit_predictions(
 2991        &mut self,
 2992        show_edit_predictions: Option<bool>,
 2993        window: &mut Window,
 2994        cx: &mut Context<Self>,
 2995    ) {
 2996        self.show_edit_predictions_override = show_edit_predictions;
 2997        self.update_edit_prediction_settings(cx);
 2998
 2999        if let Some(false) = show_edit_predictions {
 3000            self.discard_edit_prediction(false, cx);
 3001        } else {
 3002            self.refresh_edit_prediction(false, true, window, cx);
 3003        }
 3004    }
 3005
 3006    fn edit_predictions_disabled_in_scope(
 3007        &self,
 3008        buffer: &Entity<Buffer>,
 3009        buffer_position: language::Anchor,
 3010        cx: &App,
 3011    ) -> bool {
 3012        let snapshot = buffer.read(cx).snapshot();
 3013        let settings = snapshot.settings_at(buffer_position, cx);
 3014
 3015        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3016            return false;
 3017        };
 3018
 3019        scope.override_name().is_some_and(|scope_name| {
 3020            settings
 3021                .edit_predictions_disabled_in
 3022                .iter()
 3023                .any(|s| s == scope_name)
 3024        })
 3025    }
 3026
 3027    pub fn set_use_modal_editing(&mut self, to: bool) {
 3028        self.use_modal_editing = to;
 3029    }
 3030
 3031    pub fn use_modal_editing(&self) -> bool {
 3032        self.use_modal_editing
 3033    }
 3034
 3035    fn selections_did_change(
 3036        &mut self,
 3037        local: bool,
 3038        old_cursor_position: &Anchor,
 3039        effects: SelectionEffects,
 3040        window: &mut Window,
 3041        cx: &mut Context<Self>,
 3042    ) {
 3043        window.invalidate_character_coordinates();
 3044
 3045        // Copy selections to primary selection buffer
 3046        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3047        if local {
 3048            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3049            let buffer_handle = self.buffer.read(cx).read(cx);
 3050
 3051            let mut text = String::new();
 3052            for (index, selection) in selections.iter().enumerate() {
 3053                let text_for_selection = buffer_handle
 3054                    .text_for_range(selection.start..selection.end)
 3055                    .collect::<String>();
 3056
 3057                text.push_str(&text_for_selection);
 3058                if index != selections.len() - 1 {
 3059                    text.push('\n');
 3060                }
 3061            }
 3062
 3063            if !text.is_empty() {
 3064                cx.write_to_primary(ClipboardItem::new_string(text));
 3065            }
 3066        }
 3067
 3068        let selection_anchors = self.selections.disjoint_anchors_arc();
 3069
 3070        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3071            self.buffer.update(cx, |buffer, cx| {
 3072                buffer.set_active_selections(
 3073                    &selection_anchors,
 3074                    self.selections.line_mode(),
 3075                    self.cursor_shape,
 3076                    cx,
 3077                )
 3078            });
 3079        }
 3080        let display_map = self
 3081            .display_map
 3082            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3083        let buffer = display_map.buffer_snapshot();
 3084        if self.selections.count() == 1 {
 3085            self.add_selections_state = None;
 3086        }
 3087        self.select_next_state = None;
 3088        self.select_prev_state = None;
 3089        self.select_syntax_node_history.try_clear();
 3090        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3091        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3092        self.take_rename(false, window, cx);
 3093
 3094        let newest_selection = self.selections.newest_anchor();
 3095        let new_cursor_position = newest_selection.head();
 3096        let selection_start = newest_selection.start;
 3097
 3098        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3099            self.push_to_nav_history(
 3100                *old_cursor_position,
 3101                Some(new_cursor_position.to_point(buffer)),
 3102                false,
 3103                effects.nav_history == Some(true),
 3104                cx,
 3105            );
 3106        }
 3107
 3108        if local {
 3109            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3110                self.register_buffer(buffer_id, cx);
 3111            }
 3112
 3113            let mut context_menu = self.context_menu.borrow_mut();
 3114            let completion_menu = match context_menu.as_ref() {
 3115                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3116                Some(CodeContextMenu::CodeActions(_)) => {
 3117                    *context_menu = None;
 3118                    None
 3119                }
 3120                None => None,
 3121            };
 3122            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3123            drop(context_menu);
 3124
 3125            if effects.completions
 3126                && let Some(completion_position) = completion_position
 3127            {
 3128                let start_offset = selection_start.to_offset(buffer);
 3129                let position_matches = start_offset == completion_position.to_offset(buffer);
 3130                let continue_showing = if position_matches {
 3131                    if self.snippet_stack.is_empty() {
 3132                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3133                            == Some(CharKind::Word)
 3134                    } else {
 3135                        // Snippet choices can be shown even when the cursor is in whitespace.
 3136                        // Dismissing the menu with actions like backspace is handled by
 3137                        // invalidation regions.
 3138                        true
 3139                    }
 3140                } else {
 3141                    false
 3142                };
 3143
 3144                if continue_showing {
 3145                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3146                } else {
 3147                    self.hide_context_menu(window, cx);
 3148                }
 3149            }
 3150
 3151            hide_hover(self, cx);
 3152
 3153            if old_cursor_position.to_display_point(&display_map).row()
 3154                != new_cursor_position.to_display_point(&display_map).row()
 3155            {
 3156                self.available_code_actions.take();
 3157            }
 3158            self.refresh_code_actions(window, cx);
 3159            self.refresh_document_highlights(cx);
 3160            refresh_linked_ranges(self, window, cx);
 3161
 3162            self.refresh_selected_text_highlights(false, window, cx);
 3163            self.refresh_matching_bracket_highlights(window, cx);
 3164            self.update_visible_edit_prediction(window, cx);
 3165            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3166            self.inline_blame_popover.take();
 3167            if self.git_blame_inline_enabled {
 3168                self.start_inline_blame_timer(window, cx);
 3169            }
 3170        }
 3171
 3172        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3173        cx.emit(EditorEvent::SelectionsChanged { local });
 3174
 3175        let selections = &self.selections.disjoint_anchors_arc();
 3176        if selections.len() == 1 {
 3177            cx.emit(SearchEvent::ActiveMatchChanged)
 3178        }
 3179        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3180            let inmemory_selections = selections
 3181                .iter()
 3182                .map(|s| {
 3183                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3184                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3185                })
 3186                .collect();
 3187            self.update_restoration_data(cx, |data| {
 3188                data.selections = inmemory_selections;
 3189            });
 3190
 3191            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3192                && let Some(workspace_id) =
 3193                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3194            {
 3195                let snapshot = self.buffer().read(cx).snapshot(cx);
 3196                let selections = selections.clone();
 3197                let background_executor = cx.background_executor().clone();
 3198                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3199                self.serialize_selections = cx.background_spawn(async move {
 3200                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3201                    let db_selections = selections
 3202                        .iter()
 3203                        .map(|selection| {
 3204                            (
 3205                                selection.start.to_offset(&snapshot),
 3206                                selection.end.to_offset(&snapshot),
 3207                            )
 3208                        })
 3209                        .collect();
 3210
 3211                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3212                        .await
 3213                        .with_context(|| {
 3214                            format!(
 3215                                "persisting editor selections for editor {editor_id}, \
 3216                                workspace {workspace_id:?}"
 3217                            )
 3218                        })
 3219                        .log_err();
 3220                });
 3221            }
 3222        }
 3223
 3224        cx.notify();
 3225    }
 3226
 3227    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3228        use text::ToOffset as _;
 3229        use text::ToPoint as _;
 3230
 3231        if self.mode.is_minimap()
 3232            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3233        {
 3234            return;
 3235        }
 3236
 3237        if !self.buffer().read(cx).is_singleton() {
 3238            return;
 3239        }
 3240
 3241        let display_snapshot = self
 3242            .display_map
 3243            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3244        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3245            return;
 3246        };
 3247        let inmemory_folds = display_snapshot
 3248            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3249            .map(|fold| {
 3250                fold.range.start.text_anchor.to_point(&snapshot)
 3251                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3252            })
 3253            .collect();
 3254        self.update_restoration_data(cx, |data| {
 3255            data.folds = inmemory_folds;
 3256        });
 3257
 3258        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3259            return;
 3260        };
 3261        let background_executor = cx.background_executor().clone();
 3262        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3263        let db_folds = display_snapshot
 3264            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3265            .map(|fold| {
 3266                (
 3267                    fold.range.start.text_anchor.to_offset(&snapshot),
 3268                    fold.range.end.text_anchor.to_offset(&snapshot),
 3269                )
 3270            })
 3271            .collect();
 3272        self.serialize_folds = cx.background_spawn(async move {
 3273            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3274            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3275                .await
 3276                .with_context(|| {
 3277                    format!(
 3278                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3279                    )
 3280                })
 3281                .log_err();
 3282        });
 3283    }
 3284
 3285    pub fn sync_selections(
 3286        &mut self,
 3287        other: Entity<Editor>,
 3288        cx: &mut Context<Self>,
 3289    ) -> gpui::Subscription {
 3290        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3291        if !other_selections.is_empty() {
 3292            self.selections.change_with(cx, |selections| {
 3293                selections.select_anchors(other_selections);
 3294            });
 3295        }
 3296
 3297        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3298            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3299                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3300                if other_selections.is_empty() {
 3301                    return;
 3302                }
 3303                this.selections.change_with(cx, |selections| {
 3304                    selections.select_anchors(other_selections);
 3305                });
 3306            }
 3307        });
 3308
 3309        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3310            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3311                let these_selections = this.selections.disjoint_anchors().to_vec();
 3312                if these_selections.is_empty() {
 3313                    return;
 3314                }
 3315                other.update(cx, |other_editor, cx| {
 3316                    other_editor.selections.change_with(cx, |selections| {
 3317                        selections.select_anchors(these_selections);
 3318                    })
 3319                });
 3320            }
 3321        });
 3322
 3323        Subscription::join(other_subscription, this_subscription)
 3324    }
 3325
 3326    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3327    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3328    /// effects of selection change occur at the end of the transaction.
 3329    pub fn change_selections<R>(
 3330        &mut self,
 3331        effects: SelectionEffects,
 3332        window: &mut Window,
 3333        cx: &mut Context<Self>,
 3334        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3335    ) -> R {
 3336        if let Some(state) = &mut self.deferred_selection_effects_state {
 3337            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3338            state.effects.completions = effects.completions;
 3339            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3340            let (changed, result) = self.selections.change_with(cx, change);
 3341            state.changed |= changed;
 3342            return result;
 3343        }
 3344        let mut state = DeferredSelectionEffectsState {
 3345            changed: false,
 3346            effects,
 3347            old_cursor_position: self.selections.newest_anchor().head(),
 3348            history_entry: SelectionHistoryEntry {
 3349                selections: self.selections.disjoint_anchors_arc(),
 3350                select_next_state: self.select_next_state.clone(),
 3351                select_prev_state: self.select_prev_state.clone(),
 3352                add_selections_state: self.add_selections_state.clone(),
 3353            },
 3354        };
 3355        let (changed, result) = self.selections.change_with(cx, change);
 3356        state.changed = state.changed || changed;
 3357        if self.defer_selection_effects {
 3358            self.deferred_selection_effects_state = Some(state);
 3359        } else {
 3360            self.apply_selection_effects(state, window, cx);
 3361        }
 3362        result
 3363    }
 3364
 3365    /// Defers the effects of selection change, so that the effects of multiple calls to
 3366    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3367    /// to selection history and the state of popovers based on selection position aren't
 3368    /// erroneously updated.
 3369    pub fn with_selection_effects_deferred<R>(
 3370        &mut self,
 3371        window: &mut Window,
 3372        cx: &mut Context<Self>,
 3373        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3374    ) -> R {
 3375        let already_deferred = self.defer_selection_effects;
 3376        self.defer_selection_effects = true;
 3377        let result = update(self, window, cx);
 3378        if !already_deferred {
 3379            self.defer_selection_effects = false;
 3380            if let Some(state) = self.deferred_selection_effects_state.take() {
 3381                self.apply_selection_effects(state, window, cx);
 3382            }
 3383        }
 3384        result
 3385    }
 3386
 3387    fn apply_selection_effects(
 3388        &mut self,
 3389        state: DeferredSelectionEffectsState,
 3390        window: &mut Window,
 3391        cx: &mut Context<Self>,
 3392    ) {
 3393        if state.changed {
 3394            self.selection_history.push(state.history_entry);
 3395
 3396            if let Some(autoscroll) = state.effects.scroll {
 3397                self.request_autoscroll(autoscroll, cx);
 3398            }
 3399
 3400            let old_cursor_position = &state.old_cursor_position;
 3401
 3402            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3403
 3404            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3405                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3406            }
 3407        }
 3408    }
 3409
 3410    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3411    where
 3412        I: IntoIterator<Item = (Range<S>, T)>,
 3413        S: ToOffset,
 3414        T: Into<Arc<str>>,
 3415    {
 3416        if self.read_only(cx) {
 3417            return;
 3418        }
 3419
 3420        self.buffer
 3421            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3422    }
 3423
 3424    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3425    where
 3426        I: IntoIterator<Item = (Range<S>, T)>,
 3427        S: ToOffset,
 3428        T: Into<Arc<str>>,
 3429    {
 3430        if self.read_only(cx) {
 3431            return;
 3432        }
 3433
 3434        self.buffer.update(cx, |buffer, cx| {
 3435            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3436        });
 3437    }
 3438
 3439    pub fn edit_with_block_indent<I, S, T>(
 3440        &mut self,
 3441        edits: I,
 3442        original_indent_columns: Vec<Option<u32>>,
 3443        cx: &mut Context<Self>,
 3444    ) where
 3445        I: IntoIterator<Item = (Range<S>, T)>,
 3446        S: ToOffset,
 3447        T: Into<Arc<str>>,
 3448    {
 3449        if self.read_only(cx) {
 3450            return;
 3451        }
 3452
 3453        self.buffer.update(cx, |buffer, cx| {
 3454            buffer.edit(
 3455                edits,
 3456                Some(AutoindentMode::Block {
 3457                    original_indent_columns,
 3458                }),
 3459                cx,
 3460            )
 3461        });
 3462    }
 3463
 3464    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3465        self.hide_context_menu(window, cx);
 3466
 3467        match phase {
 3468            SelectPhase::Begin {
 3469                position,
 3470                add,
 3471                click_count,
 3472            } => self.begin_selection(position, add, click_count, window, cx),
 3473            SelectPhase::BeginColumnar {
 3474                position,
 3475                goal_column,
 3476                reset,
 3477                mode,
 3478            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3479            SelectPhase::Extend {
 3480                position,
 3481                click_count,
 3482            } => self.extend_selection(position, click_count, window, cx),
 3483            SelectPhase::Update {
 3484                position,
 3485                goal_column,
 3486                scroll_delta,
 3487            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3488            SelectPhase::End => self.end_selection(window, cx),
 3489        }
 3490    }
 3491
 3492    fn extend_selection(
 3493        &mut self,
 3494        position: DisplayPoint,
 3495        click_count: usize,
 3496        window: &mut Window,
 3497        cx: &mut Context<Self>,
 3498    ) {
 3499        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3500        let tail = self.selections.newest::<usize>(&display_map).tail();
 3501        let click_count = click_count.max(match self.selections.select_mode() {
 3502            SelectMode::Character => 1,
 3503            SelectMode::Word(_) => 2,
 3504            SelectMode::Line(_) => 3,
 3505            SelectMode::All => 4,
 3506        });
 3507        self.begin_selection(position, false, click_count, window, cx);
 3508
 3509        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3510
 3511        let current_selection = match self.selections.select_mode() {
 3512            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3513            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3514        };
 3515
 3516        let mut pending_selection = self
 3517            .selections
 3518            .pending_anchor()
 3519            .cloned()
 3520            .expect("extend_selection not called with pending selection");
 3521
 3522        if pending_selection
 3523            .start
 3524            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3525            == Ordering::Greater
 3526        {
 3527            pending_selection.start = current_selection.start;
 3528        }
 3529        if pending_selection
 3530            .end
 3531            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3532            == Ordering::Less
 3533        {
 3534            pending_selection.end = current_selection.end;
 3535            pending_selection.reversed = true;
 3536        }
 3537
 3538        let mut pending_mode = self.selections.pending_mode().unwrap();
 3539        match &mut pending_mode {
 3540            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3541            _ => {}
 3542        }
 3543
 3544        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3545            SelectionEffects::scroll(Autoscroll::fit())
 3546        } else {
 3547            SelectionEffects::no_scroll()
 3548        };
 3549
 3550        self.change_selections(effects, window, cx, |s| {
 3551            s.set_pending(pending_selection.clone(), pending_mode);
 3552            s.set_is_extending(true);
 3553        });
 3554    }
 3555
 3556    fn begin_selection(
 3557        &mut self,
 3558        position: DisplayPoint,
 3559        add: bool,
 3560        click_count: usize,
 3561        window: &mut Window,
 3562        cx: &mut Context<Self>,
 3563    ) {
 3564        if !self.focus_handle.is_focused(window) {
 3565            self.last_focused_descendant = None;
 3566            window.focus(&self.focus_handle);
 3567        }
 3568
 3569        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3570        let buffer = display_map.buffer_snapshot();
 3571        let position = display_map.clip_point(position, Bias::Left);
 3572
 3573        let start;
 3574        let end;
 3575        let mode;
 3576        let mut auto_scroll;
 3577        match click_count {
 3578            1 => {
 3579                start = buffer.anchor_before(position.to_point(&display_map));
 3580                end = start;
 3581                mode = SelectMode::Character;
 3582                auto_scroll = true;
 3583            }
 3584            2 => {
 3585                let position = display_map
 3586                    .clip_point(position, Bias::Left)
 3587                    .to_offset(&display_map, Bias::Left);
 3588                let (range, _) = buffer.surrounding_word(position, None);
 3589                start = buffer.anchor_before(range.start);
 3590                end = buffer.anchor_before(range.end);
 3591                mode = SelectMode::Word(start..end);
 3592                auto_scroll = true;
 3593            }
 3594            3 => {
 3595                let position = display_map
 3596                    .clip_point(position, Bias::Left)
 3597                    .to_point(&display_map);
 3598                let line_start = display_map.prev_line_boundary(position).0;
 3599                let next_line_start = buffer.clip_point(
 3600                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3601                    Bias::Left,
 3602                );
 3603                start = buffer.anchor_before(line_start);
 3604                end = buffer.anchor_before(next_line_start);
 3605                mode = SelectMode::Line(start..end);
 3606                auto_scroll = true;
 3607            }
 3608            _ => {
 3609                start = buffer.anchor_before(0);
 3610                end = buffer.anchor_before(buffer.len());
 3611                mode = SelectMode::All;
 3612                auto_scroll = false;
 3613            }
 3614        }
 3615        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3616
 3617        let point_to_delete: Option<usize> = {
 3618            let selected_points: Vec<Selection<Point>> =
 3619                self.selections.disjoint_in_range(start..end, &display_map);
 3620
 3621            if !add || click_count > 1 {
 3622                None
 3623            } else if !selected_points.is_empty() {
 3624                Some(selected_points[0].id)
 3625            } else {
 3626                let clicked_point_already_selected =
 3627                    self.selections.disjoint_anchors().iter().find(|selection| {
 3628                        selection.start.to_point(buffer) == start.to_point(buffer)
 3629                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3630                    });
 3631
 3632                clicked_point_already_selected.map(|selection| selection.id)
 3633            }
 3634        };
 3635
 3636        let selections_count = self.selections.count();
 3637        let effects = if auto_scroll {
 3638            SelectionEffects::default()
 3639        } else {
 3640            SelectionEffects::no_scroll()
 3641        };
 3642
 3643        self.change_selections(effects, window, cx, |s| {
 3644            if let Some(point_to_delete) = point_to_delete {
 3645                s.delete(point_to_delete);
 3646
 3647                if selections_count == 1 {
 3648                    s.set_pending_anchor_range(start..end, mode);
 3649                }
 3650            } else {
 3651                if !add {
 3652                    s.clear_disjoint();
 3653                }
 3654
 3655                s.set_pending_anchor_range(start..end, mode);
 3656            }
 3657        });
 3658    }
 3659
 3660    fn begin_columnar_selection(
 3661        &mut self,
 3662        position: DisplayPoint,
 3663        goal_column: u32,
 3664        reset: bool,
 3665        mode: ColumnarMode,
 3666        window: &mut Window,
 3667        cx: &mut Context<Self>,
 3668    ) {
 3669        if !self.focus_handle.is_focused(window) {
 3670            self.last_focused_descendant = None;
 3671            window.focus(&self.focus_handle);
 3672        }
 3673
 3674        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3675
 3676        if reset {
 3677            let pointer_position = display_map
 3678                .buffer_snapshot()
 3679                .anchor_before(position.to_point(&display_map));
 3680
 3681            self.change_selections(
 3682                SelectionEffects::scroll(Autoscroll::newest()),
 3683                window,
 3684                cx,
 3685                |s| {
 3686                    s.clear_disjoint();
 3687                    s.set_pending_anchor_range(
 3688                        pointer_position..pointer_position,
 3689                        SelectMode::Character,
 3690                    );
 3691                },
 3692            );
 3693        };
 3694
 3695        let tail = self.selections.newest::<Point>(&display_map).tail();
 3696        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3697        self.columnar_selection_state = match mode {
 3698            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3699                selection_tail: selection_anchor,
 3700                display_point: if reset {
 3701                    if position.column() != goal_column {
 3702                        Some(DisplayPoint::new(position.row(), goal_column))
 3703                    } else {
 3704                        None
 3705                    }
 3706                } else {
 3707                    None
 3708                },
 3709            }),
 3710            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3711                selection_tail: selection_anchor,
 3712            }),
 3713        };
 3714
 3715        if !reset {
 3716            self.select_columns(position, goal_column, &display_map, window, cx);
 3717        }
 3718    }
 3719
 3720    fn update_selection(
 3721        &mut self,
 3722        position: DisplayPoint,
 3723        goal_column: u32,
 3724        scroll_delta: gpui::Point<f32>,
 3725        window: &mut Window,
 3726        cx: &mut Context<Self>,
 3727    ) {
 3728        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3729
 3730        if self.columnar_selection_state.is_some() {
 3731            self.select_columns(position, goal_column, &display_map, window, cx);
 3732        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3733            let buffer = display_map.buffer_snapshot();
 3734            let head;
 3735            let tail;
 3736            let mode = self.selections.pending_mode().unwrap();
 3737            match &mode {
 3738                SelectMode::Character => {
 3739                    head = position.to_point(&display_map);
 3740                    tail = pending.tail().to_point(buffer);
 3741                }
 3742                SelectMode::Word(original_range) => {
 3743                    let offset = display_map
 3744                        .clip_point(position, Bias::Left)
 3745                        .to_offset(&display_map, Bias::Left);
 3746                    let original_range = original_range.to_offset(buffer);
 3747
 3748                    let head_offset = if buffer.is_inside_word(offset, None)
 3749                        || original_range.contains(&offset)
 3750                    {
 3751                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3752                        if word_range.start < original_range.start {
 3753                            word_range.start
 3754                        } else {
 3755                            word_range.end
 3756                        }
 3757                    } else {
 3758                        offset
 3759                    };
 3760
 3761                    head = head_offset.to_point(buffer);
 3762                    if head_offset <= original_range.start {
 3763                        tail = original_range.end.to_point(buffer);
 3764                    } else {
 3765                        tail = original_range.start.to_point(buffer);
 3766                    }
 3767                }
 3768                SelectMode::Line(original_range) => {
 3769                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3770
 3771                    let position = display_map
 3772                        .clip_point(position, Bias::Left)
 3773                        .to_point(&display_map);
 3774                    let line_start = display_map.prev_line_boundary(position).0;
 3775                    let next_line_start = buffer.clip_point(
 3776                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3777                        Bias::Left,
 3778                    );
 3779
 3780                    if line_start < original_range.start {
 3781                        head = line_start
 3782                    } else {
 3783                        head = next_line_start
 3784                    }
 3785
 3786                    if head <= original_range.start {
 3787                        tail = original_range.end;
 3788                    } else {
 3789                        tail = original_range.start;
 3790                    }
 3791                }
 3792                SelectMode::All => {
 3793                    return;
 3794                }
 3795            };
 3796
 3797            if head < tail {
 3798                pending.start = buffer.anchor_before(head);
 3799                pending.end = buffer.anchor_before(tail);
 3800                pending.reversed = true;
 3801            } else {
 3802                pending.start = buffer.anchor_before(tail);
 3803                pending.end = buffer.anchor_before(head);
 3804                pending.reversed = false;
 3805            }
 3806
 3807            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3808                s.set_pending(pending.clone(), mode);
 3809            });
 3810        } else {
 3811            log::error!("update_selection dispatched with no pending selection");
 3812            return;
 3813        }
 3814
 3815        self.apply_scroll_delta(scroll_delta, window, cx);
 3816        cx.notify();
 3817    }
 3818
 3819    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3820        self.columnar_selection_state.take();
 3821        if let Some(pending_mode) = self.selections.pending_mode() {
 3822            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3823            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3824                s.select(selections);
 3825                s.clear_pending();
 3826                if s.is_extending() {
 3827                    s.set_is_extending(false);
 3828                } else {
 3829                    s.set_select_mode(pending_mode);
 3830                }
 3831            });
 3832        }
 3833    }
 3834
 3835    fn select_columns(
 3836        &mut self,
 3837        head: DisplayPoint,
 3838        goal_column: u32,
 3839        display_map: &DisplaySnapshot,
 3840        window: &mut Window,
 3841        cx: &mut Context<Self>,
 3842    ) {
 3843        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3844            return;
 3845        };
 3846
 3847        let tail = match columnar_state {
 3848            ColumnarSelectionState::FromMouse {
 3849                selection_tail,
 3850                display_point,
 3851            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3852            ColumnarSelectionState::FromSelection { selection_tail } => {
 3853                selection_tail.to_display_point(display_map)
 3854            }
 3855        };
 3856
 3857        let start_row = cmp::min(tail.row(), head.row());
 3858        let end_row = cmp::max(tail.row(), head.row());
 3859        let start_column = cmp::min(tail.column(), goal_column);
 3860        let end_column = cmp::max(tail.column(), goal_column);
 3861        let reversed = start_column < tail.column();
 3862
 3863        let selection_ranges = (start_row.0..=end_row.0)
 3864            .map(DisplayRow)
 3865            .filter_map(|row| {
 3866                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3867                    || start_column <= display_map.line_len(row))
 3868                    && !display_map.is_block_line(row)
 3869                {
 3870                    let start = display_map
 3871                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3872                        .to_point(display_map);
 3873                    let end = display_map
 3874                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3875                        .to_point(display_map);
 3876                    if reversed {
 3877                        Some(end..start)
 3878                    } else {
 3879                        Some(start..end)
 3880                    }
 3881                } else {
 3882                    None
 3883                }
 3884            })
 3885            .collect::<Vec<_>>();
 3886        if selection_ranges.is_empty() {
 3887            return;
 3888        }
 3889
 3890        let ranges = match columnar_state {
 3891            ColumnarSelectionState::FromMouse { .. } => {
 3892                let mut non_empty_ranges = selection_ranges
 3893                    .iter()
 3894                    .filter(|selection_range| selection_range.start != selection_range.end)
 3895                    .peekable();
 3896                if non_empty_ranges.peek().is_some() {
 3897                    non_empty_ranges.cloned().collect()
 3898                } else {
 3899                    selection_ranges
 3900                }
 3901            }
 3902            _ => selection_ranges,
 3903        };
 3904
 3905        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3906            s.select_ranges(ranges);
 3907        });
 3908        cx.notify();
 3909    }
 3910
 3911    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3912        self.selections
 3913            .all_adjusted(snapshot)
 3914            .iter()
 3915            .any(|selection| !selection.is_empty())
 3916    }
 3917
 3918    pub fn has_pending_nonempty_selection(&self) -> bool {
 3919        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3920            Some(Selection { start, end, .. }) => start != end,
 3921            None => false,
 3922        };
 3923
 3924        pending_nonempty_selection
 3925            || (self.columnar_selection_state.is_some()
 3926                && self.selections.disjoint_anchors().len() > 1)
 3927    }
 3928
 3929    pub fn has_pending_selection(&self) -> bool {
 3930        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3931    }
 3932
 3933    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3934        self.selection_mark_mode = false;
 3935        self.selection_drag_state = SelectionDragState::None;
 3936
 3937        if self.clear_expanded_diff_hunks(cx) {
 3938            cx.notify();
 3939            return;
 3940        }
 3941        if self.dismiss_menus_and_popups(true, window, cx) {
 3942            return;
 3943        }
 3944
 3945        if self.mode.is_full()
 3946            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3947        {
 3948            return;
 3949        }
 3950
 3951        cx.propagate();
 3952    }
 3953
 3954    pub fn dismiss_menus_and_popups(
 3955        &mut self,
 3956        is_user_requested: bool,
 3957        window: &mut Window,
 3958        cx: &mut Context<Self>,
 3959    ) -> bool {
 3960        if self.take_rename(false, window, cx).is_some() {
 3961            return true;
 3962        }
 3963
 3964        if self.hide_blame_popover(true, cx) {
 3965            return true;
 3966        }
 3967
 3968        if hide_hover(self, cx) {
 3969            return true;
 3970        }
 3971
 3972        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3973            return true;
 3974        }
 3975
 3976        if self.hide_context_menu(window, cx).is_some() {
 3977            return true;
 3978        }
 3979
 3980        if self.mouse_context_menu.take().is_some() {
 3981            return true;
 3982        }
 3983
 3984        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3985            return true;
 3986        }
 3987
 3988        if self.snippet_stack.pop().is_some() {
 3989            return true;
 3990        }
 3991
 3992        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3993            self.dismiss_diagnostics(cx);
 3994            return true;
 3995        }
 3996
 3997        false
 3998    }
 3999
 4000    fn linked_editing_ranges_for(
 4001        &self,
 4002        selection: Range<text::Anchor>,
 4003        cx: &App,
 4004    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4005        if self.linked_edit_ranges.is_empty() {
 4006            return None;
 4007        }
 4008        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4009            selection.end.buffer_id.and_then(|end_buffer_id| {
 4010                if selection.start.buffer_id != Some(end_buffer_id) {
 4011                    return None;
 4012                }
 4013                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4014                let snapshot = buffer.read(cx).snapshot();
 4015                self.linked_edit_ranges
 4016                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4017                    .map(|ranges| (ranges, snapshot, buffer))
 4018            })?;
 4019        use text::ToOffset as TO;
 4020        // find offset from the start of current range to current cursor position
 4021        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4022
 4023        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4024        let start_difference = start_offset - start_byte_offset;
 4025        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4026        let end_difference = end_offset - start_byte_offset;
 4027        // Current range has associated linked ranges.
 4028        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4029        for range in linked_ranges.iter() {
 4030            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4031            let end_offset = start_offset + end_difference;
 4032            let start_offset = start_offset + start_difference;
 4033            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4034                continue;
 4035            }
 4036            if self.selections.disjoint_anchor_ranges().any(|s| {
 4037                if s.start.buffer_id != selection.start.buffer_id
 4038                    || s.end.buffer_id != selection.end.buffer_id
 4039                {
 4040                    return false;
 4041                }
 4042                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4043                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4044            }) {
 4045                continue;
 4046            }
 4047            let start = buffer_snapshot.anchor_after(start_offset);
 4048            let end = buffer_snapshot.anchor_after(end_offset);
 4049            linked_edits
 4050                .entry(buffer.clone())
 4051                .or_default()
 4052                .push(start..end);
 4053        }
 4054        Some(linked_edits)
 4055    }
 4056
 4057    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4058        let text: Arc<str> = text.into();
 4059
 4060        if self.read_only(cx) {
 4061            return;
 4062        }
 4063
 4064        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4065
 4066        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4067        let mut bracket_inserted = false;
 4068        let mut edits = Vec::new();
 4069        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4070        let mut new_selections = Vec::with_capacity(selections.len());
 4071        let mut new_autoclose_regions = Vec::new();
 4072        let snapshot = self.buffer.read(cx).read(cx);
 4073        let mut clear_linked_edit_ranges = false;
 4074
 4075        for (selection, autoclose_region) in
 4076            self.selections_with_autoclose_regions(selections, &snapshot)
 4077        {
 4078            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4079                // Determine if the inserted text matches the opening or closing
 4080                // bracket of any of this language's bracket pairs.
 4081                let mut bracket_pair = None;
 4082                let mut is_bracket_pair_start = false;
 4083                let mut is_bracket_pair_end = false;
 4084                if !text.is_empty() {
 4085                    let mut bracket_pair_matching_end = None;
 4086                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4087                    //  and they are removing the character that triggered IME popup.
 4088                    for (pair, enabled) in scope.brackets() {
 4089                        if !pair.close && !pair.surround {
 4090                            continue;
 4091                        }
 4092
 4093                        if enabled && pair.start.ends_with(text.as_ref()) {
 4094                            let prefix_len = pair.start.len() - text.len();
 4095                            let preceding_text_matches_prefix = prefix_len == 0
 4096                                || (selection.start.column >= (prefix_len as u32)
 4097                                    && snapshot.contains_str_at(
 4098                                        Point::new(
 4099                                            selection.start.row,
 4100                                            selection.start.column - (prefix_len as u32),
 4101                                        ),
 4102                                        &pair.start[..prefix_len],
 4103                                    ));
 4104                            if preceding_text_matches_prefix {
 4105                                bracket_pair = Some(pair.clone());
 4106                                is_bracket_pair_start = true;
 4107                                break;
 4108                            }
 4109                        }
 4110                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4111                        {
 4112                            // take first bracket pair matching end, but don't break in case a later bracket
 4113                            // pair matches start
 4114                            bracket_pair_matching_end = Some(pair.clone());
 4115                        }
 4116                    }
 4117                    if let Some(end) = bracket_pair_matching_end
 4118                        && bracket_pair.is_none()
 4119                    {
 4120                        bracket_pair = Some(end);
 4121                        is_bracket_pair_end = true;
 4122                    }
 4123                }
 4124
 4125                if let Some(bracket_pair) = bracket_pair {
 4126                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4127                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4128                    let auto_surround =
 4129                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4130                    if selection.is_empty() {
 4131                        if is_bracket_pair_start {
 4132                            // If the inserted text is a suffix of an opening bracket and the
 4133                            // selection is preceded by the rest of the opening bracket, then
 4134                            // insert the closing bracket.
 4135                            let following_text_allows_autoclose = snapshot
 4136                                .chars_at(selection.start)
 4137                                .next()
 4138                                .is_none_or(|c| scope.should_autoclose_before(c));
 4139
 4140                            let preceding_text_allows_autoclose = selection.start.column == 0
 4141                                || snapshot
 4142                                    .reversed_chars_at(selection.start)
 4143                                    .next()
 4144                                    .is_none_or(|c| {
 4145                                        bracket_pair.start != bracket_pair.end
 4146                                            || !snapshot
 4147                                                .char_classifier_at(selection.start)
 4148                                                .is_word(c)
 4149                                    });
 4150
 4151                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4152                                && bracket_pair.start.len() == 1
 4153                            {
 4154                                let target = bracket_pair.start.chars().next().unwrap();
 4155                                let current_line_count = snapshot
 4156                                    .reversed_chars_at(selection.start)
 4157                                    .take_while(|&c| c != '\n')
 4158                                    .filter(|&c| c == target)
 4159                                    .count();
 4160                                current_line_count % 2 == 1
 4161                            } else {
 4162                                false
 4163                            };
 4164
 4165                            if autoclose
 4166                                && bracket_pair.close
 4167                                && following_text_allows_autoclose
 4168                                && preceding_text_allows_autoclose
 4169                                && !is_closing_quote
 4170                            {
 4171                                let anchor = snapshot.anchor_before(selection.end);
 4172                                new_selections.push((selection.map(|_| anchor), text.len()));
 4173                                new_autoclose_regions.push((
 4174                                    anchor,
 4175                                    text.len(),
 4176                                    selection.id,
 4177                                    bracket_pair.clone(),
 4178                                ));
 4179                                edits.push((
 4180                                    selection.range(),
 4181                                    format!("{}{}", text, bracket_pair.end).into(),
 4182                                ));
 4183                                bracket_inserted = true;
 4184                                continue;
 4185                            }
 4186                        }
 4187
 4188                        if let Some(region) = autoclose_region {
 4189                            // If the selection is followed by an auto-inserted closing bracket,
 4190                            // then don't insert that closing bracket again; just move the selection
 4191                            // past the closing bracket.
 4192                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4193                                && text.as_ref() == region.pair.end.as_str()
 4194                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4195                            if should_skip {
 4196                                let anchor = snapshot.anchor_after(selection.end);
 4197                                new_selections
 4198                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4199                                continue;
 4200                            }
 4201                        }
 4202
 4203                        let always_treat_brackets_as_autoclosed = snapshot
 4204                            .language_settings_at(selection.start, cx)
 4205                            .always_treat_brackets_as_autoclosed;
 4206                        if always_treat_brackets_as_autoclosed
 4207                            && is_bracket_pair_end
 4208                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4209                        {
 4210                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4211                            // and the inserted text is a closing bracket and the selection is followed
 4212                            // by the closing bracket then move the selection past the closing bracket.
 4213                            let anchor = snapshot.anchor_after(selection.end);
 4214                            new_selections.push((selection.map(|_| anchor), text.len()));
 4215                            continue;
 4216                        }
 4217                    }
 4218                    // If an opening bracket is 1 character long and is typed while
 4219                    // text is selected, then surround that text with the bracket pair.
 4220                    else if auto_surround
 4221                        && bracket_pair.surround
 4222                        && is_bracket_pair_start
 4223                        && bracket_pair.start.chars().count() == 1
 4224                    {
 4225                        edits.push((selection.start..selection.start, text.clone()));
 4226                        edits.push((
 4227                            selection.end..selection.end,
 4228                            bracket_pair.end.as_str().into(),
 4229                        ));
 4230                        bracket_inserted = true;
 4231                        new_selections.push((
 4232                            Selection {
 4233                                id: selection.id,
 4234                                start: snapshot.anchor_after(selection.start),
 4235                                end: snapshot.anchor_before(selection.end),
 4236                                reversed: selection.reversed,
 4237                                goal: selection.goal,
 4238                            },
 4239                            0,
 4240                        ));
 4241                        continue;
 4242                    }
 4243                }
 4244            }
 4245
 4246            if self.auto_replace_emoji_shortcode
 4247                && selection.is_empty()
 4248                && text.as_ref().ends_with(':')
 4249                && let Some(possible_emoji_short_code) =
 4250                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4251                && !possible_emoji_short_code.is_empty()
 4252                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4253            {
 4254                let emoji_shortcode_start = Point::new(
 4255                    selection.start.row,
 4256                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4257                );
 4258
 4259                // Remove shortcode from buffer
 4260                edits.push((
 4261                    emoji_shortcode_start..selection.start,
 4262                    "".to_string().into(),
 4263                ));
 4264                new_selections.push((
 4265                    Selection {
 4266                        id: selection.id,
 4267                        start: snapshot.anchor_after(emoji_shortcode_start),
 4268                        end: snapshot.anchor_before(selection.start),
 4269                        reversed: selection.reversed,
 4270                        goal: selection.goal,
 4271                    },
 4272                    0,
 4273                ));
 4274
 4275                // Insert emoji
 4276                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4277                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4278                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4279
 4280                continue;
 4281            }
 4282
 4283            // If not handling any auto-close operation, then just replace the selected
 4284            // text with the given input and move the selection to the end of the
 4285            // newly inserted text.
 4286            let anchor = snapshot.anchor_after(selection.end);
 4287            if !self.linked_edit_ranges.is_empty() {
 4288                let start_anchor = snapshot.anchor_before(selection.start);
 4289
 4290                let is_word_char = text.chars().next().is_none_or(|char| {
 4291                    let classifier = snapshot
 4292                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4293                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4294                    classifier.is_word(char)
 4295                });
 4296
 4297                if is_word_char {
 4298                    if let Some(ranges) = self
 4299                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4300                    {
 4301                        for (buffer, edits) in ranges {
 4302                            linked_edits
 4303                                .entry(buffer.clone())
 4304                                .or_default()
 4305                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4306                        }
 4307                    }
 4308                } else {
 4309                    clear_linked_edit_ranges = true;
 4310                }
 4311            }
 4312
 4313            new_selections.push((selection.map(|_| anchor), 0));
 4314            edits.push((selection.start..selection.end, text.clone()));
 4315        }
 4316
 4317        drop(snapshot);
 4318
 4319        self.transact(window, cx, |this, window, cx| {
 4320            if clear_linked_edit_ranges {
 4321                this.linked_edit_ranges.clear();
 4322            }
 4323            let initial_buffer_versions =
 4324                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4325
 4326            this.buffer.update(cx, |buffer, cx| {
 4327                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4328            });
 4329            for (buffer, edits) in linked_edits {
 4330                buffer.update(cx, |buffer, cx| {
 4331                    let snapshot = buffer.snapshot();
 4332                    let edits = edits
 4333                        .into_iter()
 4334                        .map(|(range, text)| {
 4335                            use text::ToPoint as TP;
 4336                            let end_point = TP::to_point(&range.end, &snapshot);
 4337                            let start_point = TP::to_point(&range.start, &snapshot);
 4338                            (start_point..end_point, text)
 4339                        })
 4340                        .sorted_by_key(|(range, _)| range.start);
 4341                    buffer.edit(edits, None, cx);
 4342                })
 4343            }
 4344            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4345            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4346            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4347            let new_selections =
 4348                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4349                    .zip(new_selection_deltas)
 4350                    .map(|(selection, delta)| Selection {
 4351                        id: selection.id,
 4352                        start: selection.start + delta,
 4353                        end: selection.end + delta,
 4354                        reversed: selection.reversed,
 4355                        goal: SelectionGoal::None,
 4356                    })
 4357                    .collect::<Vec<_>>();
 4358
 4359            let mut i = 0;
 4360            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4361                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4362                let start = map.buffer_snapshot().anchor_before(position);
 4363                let end = map.buffer_snapshot().anchor_after(position);
 4364                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4365                    match existing_state
 4366                        .range
 4367                        .start
 4368                        .cmp(&start, map.buffer_snapshot())
 4369                    {
 4370                        Ordering::Less => i += 1,
 4371                        Ordering::Greater => break,
 4372                        Ordering::Equal => {
 4373                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4374                                Ordering::Less => i += 1,
 4375                                Ordering::Equal => break,
 4376                                Ordering::Greater => break,
 4377                            }
 4378                        }
 4379                    }
 4380                }
 4381                this.autoclose_regions.insert(
 4382                    i,
 4383                    AutocloseRegion {
 4384                        selection_id,
 4385                        range: start..end,
 4386                        pair,
 4387                    },
 4388                );
 4389            }
 4390
 4391            let had_active_edit_prediction = this.has_active_edit_prediction();
 4392            this.change_selections(
 4393                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4394                window,
 4395                cx,
 4396                |s| s.select(new_selections),
 4397            );
 4398
 4399            if !bracket_inserted
 4400                && let Some(on_type_format_task) =
 4401                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4402            {
 4403                on_type_format_task.detach_and_log_err(cx);
 4404            }
 4405
 4406            let editor_settings = EditorSettings::get_global(cx);
 4407            if bracket_inserted
 4408                && (editor_settings.auto_signature_help
 4409                    || editor_settings.show_signature_help_after_edits)
 4410            {
 4411                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4412            }
 4413
 4414            let trigger_in_words =
 4415                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4416            if this.hard_wrap.is_some() {
 4417                let latest: Range<Point> = this.selections.newest(&map).range();
 4418                if latest.is_empty()
 4419                    && this
 4420                        .buffer()
 4421                        .read(cx)
 4422                        .snapshot(cx)
 4423                        .line_len(MultiBufferRow(latest.start.row))
 4424                        == latest.start.column
 4425                {
 4426                    this.rewrap_impl(
 4427                        RewrapOptions {
 4428                            override_language_settings: true,
 4429                            preserve_existing_whitespace: true,
 4430                        },
 4431                        cx,
 4432                    )
 4433                }
 4434            }
 4435            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4436            refresh_linked_ranges(this, window, cx);
 4437            this.refresh_edit_prediction(true, false, window, cx);
 4438            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4439        });
 4440    }
 4441
 4442    fn find_possible_emoji_shortcode_at_position(
 4443        snapshot: &MultiBufferSnapshot,
 4444        position: Point,
 4445    ) -> Option<String> {
 4446        let mut chars = Vec::new();
 4447        let mut found_colon = false;
 4448        for char in snapshot.reversed_chars_at(position).take(100) {
 4449            // Found a possible emoji shortcode in the middle of the buffer
 4450            if found_colon {
 4451                if char.is_whitespace() {
 4452                    chars.reverse();
 4453                    return Some(chars.iter().collect());
 4454                }
 4455                // If the previous character is not a whitespace, we are in the middle of a word
 4456                // and we only want to complete the shortcode if the word is made up of other emojis
 4457                let mut containing_word = String::new();
 4458                for ch in snapshot
 4459                    .reversed_chars_at(position)
 4460                    .skip(chars.len() + 1)
 4461                    .take(100)
 4462                {
 4463                    if ch.is_whitespace() {
 4464                        break;
 4465                    }
 4466                    containing_word.push(ch);
 4467                }
 4468                let containing_word = containing_word.chars().rev().collect::<String>();
 4469                if util::word_consists_of_emojis(containing_word.as_str()) {
 4470                    chars.reverse();
 4471                    return Some(chars.iter().collect());
 4472                }
 4473            }
 4474
 4475            if char.is_whitespace() || !char.is_ascii() {
 4476                return None;
 4477            }
 4478            if char == ':' {
 4479                found_colon = true;
 4480            } else {
 4481                chars.push(char);
 4482            }
 4483        }
 4484        // Found a possible emoji shortcode at the beginning of the buffer
 4485        chars.reverse();
 4486        Some(chars.iter().collect())
 4487    }
 4488
 4489    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4490        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4491        self.transact(window, cx, |this, window, cx| {
 4492            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4493                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4494                let multi_buffer = this.buffer.read(cx);
 4495                let buffer = multi_buffer.snapshot(cx);
 4496                selections
 4497                    .iter()
 4498                    .map(|selection| {
 4499                        let start_point = selection.start.to_point(&buffer);
 4500                        let mut existing_indent =
 4501                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4502                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4503                        let start = selection.start;
 4504                        let end = selection.end;
 4505                        let selection_is_empty = start == end;
 4506                        let language_scope = buffer.language_scope_at(start);
 4507                        let (
 4508                            comment_delimiter,
 4509                            doc_delimiter,
 4510                            insert_extra_newline,
 4511                            indent_on_newline,
 4512                            indent_on_extra_newline,
 4513                        ) = if let Some(language) = &language_scope {
 4514                            let mut insert_extra_newline =
 4515                                insert_extra_newline_brackets(&buffer, start..end, language)
 4516                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4517
 4518                            // Comment extension on newline is allowed only for cursor selections
 4519                            let comment_delimiter = maybe!({
 4520                                if !selection_is_empty {
 4521                                    return None;
 4522                                }
 4523
 4524                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4525                                    return None;
 4526                                }
 4527
 4528                                let delimiters = language.line_comment_prefixes();
 4529                                let max_len_of_delimiter =
 4530                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4531                                let (snapshot, range) =
 4532                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4533
 4534                                let num_of_whitespaces = snapshot
 4535                                    .chars_for_range(range.clone())
 4536                                    .take_while(|c| c.is_whitespace())
 4537                                    .count();
 4538                                let comment_candidate = snapshot
 4539                                    .chars_for_range(range.clone())
 4540                                    .skip(num_of_whitespaces)
 4541                                    .take(max_len_of_delimiter)
 4542                                    .collect::<String>();
 4543                                let (delimiter, trimmed_len) = delimiters
 4544                                    .iter()
 4545                                    .filter_map(|delimiter| {
 4546                                        let prefix = delimiter.trim_end();
 4547                                        if comment_candidate.starts_with(prefix) {
 4548                                            Some((delimiter, prefix.len()))
 4549                                        } else {
 4550                                            None
 4551                                        }
 4552                                    })
 4553                                    .max_by_key(|(_, len)| *len)?;
 4554
 4555                                if let Some(BlockCommentConfig {
 4556                                    start: block_start, ..
 4557                                }) = language.block_comment()
 4558                                {
 4559                                    let block_start_trimmed = block_start.trim_end();
 4560                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4561                                        let line_content = snapshot
 4562                                            .chars_for_range(range)
 4563                                            .skip(num_of_whitespaces)
 4564                                            .take(block_start_trimmed.len())
 4565                                            .collect::<String>();
 4566
 4567                                        if line_content.starts_with(block_start_trimmed) {
 4568                                            return None;
 4569                                        }
 4570                                    }
 4571                                }
 4572
 4573                                let cursor_is_placed_after_comment_marker =
 4574                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4575                                if cursor_is_placed_after_comment_marker {
 4576                                    Some(delimiter.clone())
 4577                                } else {
 4578                                    None
 4579                                }
 4580                            });
 4581
 4582                            let mut indent_on_newline = IndentSize::spaces(0);
 4583                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4584
 4585                            let doc_delimiter = maybe!({
 4586                                if !selection_is_empty {
 4587                                    return None;
 4588                                }
 4589
 4590                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4591                                    return None;
 4592                                }
 4593
 4594                                let BlockCommentConfig {
 4595                                    start: start_tag,
 4596                                    end: end_tag,
 4597                                    prefix: delimiter,
 4598                                    tab_size: len,
 4599                                } = language.documentation_comment()?;
 4600                                let is_within_block_comment = buffer
 4601                                    .language_scope_at(start_point)
 4602                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4603                                if !is_within_block_comment {
 4604                                    return None;
 4605                                }
 4606
 4607                                let (snapshot, range) =
 4608                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4609
 4610                                let num_of_whitespaces = snapshot
 4611                                    .chars_for_range(range.clone())
 4612                                    .take_while(|c| c.is_whitespace())
 4613                                    .count();
 4614
 4615                                // 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.
 4616                                let column = start_point.column;
 4617                                let cursor_is_after_start_tag = {
 4618                                    let start_tag_len = start_tag.len();
 4619                                    let start_tag_line = snapshot
 4620                                        .chars_for_range(range.clone())
 4621                                        .skip(num_of_whitespaces)
 4622                                        .take(start_tag_len)
 4623                                        .collect::<String>();
 4624                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4625                                        num_of_whitespaces + start_tag_len <= column as usize
 4626                                    } else {
 4627                                        false
 4628                                    }
 4629                                };
 4630
 4631                                let cursor_is_after_delimiter = {
 4632                                    let delimiter_trim = delimiter.trim_end();
 4633                                    let delimiter_line = snapshot
 4634                                        .chars_for_range(range.clone())
 4635                                        .skip(num_of_whitespaces)
 4636                                        .take(delimiter_trim.len())
 4637                                        .collect::<String>();
 4638                                    if delimiter_line.starts_with(delimiter_trim) {
 4639                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4640                                    } else {
 4641                                        false
 4642                                    }
 4643                                };
 4644
 4645                                let cursor_is_before_end_tag_if_exists = {
 4646                                    let mut char_position = 0u32;
 4647                                    let mut end_tag_offset = None;
 4648
 4649                                    'outer: for chunk in snapshot.text_for_range(range) {
 4650                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4651                                            let chars_before_match =
 4652                                                chunk[..byte_pos].chars().count() as u32;
 4653                                            end_tag_offset =
 4654                                                Some(char_position + chars_before_match);
 4655                                            break 'outer;
 4656                                        }
 4657                                        char_position += chunk.chars().count() as u32;
 4658                                    }
 4659
 4660                                    if let Some(end_tag_offset) = end_tag_offset {
 4661                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4662                                        if cursor_is_after_start_tag {
 4663                                            if cursor_is_before_end_tag {
 4664                                                insert_extra_newline = true;
 4665                                            }
 4666                                            let cursor_is_at_start_of_end_tag =
 4667                                                column == end_tag_offset;
 4668                                            if cursor_is_at_start_of_end_tag {
 4669                                                indent_on_extra_newline.len = *len;
 4670                                            }
 4671                                        }
 4672                                        cursor_is_before_end_tag
 4673                                    } else {
 4674                                        true
 4675                                    }
 4676                                };
 4677
 4678                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4679                                    && cursor_is_before_end_tag_if_exists
 4680                                {
 4681                                    if cursor_is_after_start_tag {
 4682                                        indent_on_newline.len = *len;
 4683                                    }
 4684                                    Some(delimiter.clone())
 4685                                } else {
 4686                                    None
 4687                                }
 4688                            });
 4689
 4690                            (
 4691                                comment_delimiter,
 4692                                doc_delimiter,
 4693                                insert_extra_newline,
 4694                                indent_on_newline,
 4695                                indent_on_extra_newline,
 4696                            )
 4697                        } else {
 4698                            (
 4699                                None,
 4700                                None,
 4701                                false,
 4702                                IndentSize::default(),
 4703                                IndentSize::default(),
 4704                            )
 4705                        };
 4706
 4707                        let prevent_auto_indent = doc_delimiter.is_some();
 4708                        let delimiter = comment_delimiter.or(doc_delimiter);
 4709
 4710                        let capacity_for_delimiter =
 4711                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4712                        let mut new_text = String::with_capacity(
 4713                            1 + capacity_for_delimiter
 4714                                + existing_indent.len as usize
 4715                                + indent_on_newline.len as usize
 4716                                + indent_on_extra_newline.len as usize,
 4717                        );
 4718                        new_text.push('\n');
 4719                        new_text.extend(existing_indent.chars());
 4720                        new_text.extend(indent_on_newline.chars());
 4721
 4722                        if let Some(delimiter) = &delimiter {
 4723                            new_text.push_str(delimiter);
 4724                        }
 4725
 4726                        if insert_extra_newline {
 4727                            new_text.push('\n');
 4728                            new_text.extend(existing_indent.chars());
 4729                            new_text.extend(indent_on_extra_newline.chars());
 4730                        }
 4731
 4732                        let anchor = buffer.anchor_after(end);
 4733                        let new_selection = selection.map(|_| anchor);
 4734                        (
 4735                            ((start..end, new_text), prevent_auto_indent),
 4736                            (insert_extra_newline, new_selection),
 4737                        )
 4738                    })
 4739                    .unzip()
 4740            };
 4741
 4742            let mut auto_indent_edits = Vec::new();
 4743            let mut edits = Vec::new();
 4744            for (edit, prevent_auto_indent) in edits_with_flags {
 4745                if prevent_auto_indent {
 4746                    edits.push(edit);
 4747                } else {
 4748                    auto_indent_edits.push(edit);
 4749                }
 4750            }
 4751            if !edits.is_empty() {
 4752                this.edit(edits, cx);
 4753            }
 4754            if !auto_indent_edits.is_empty() {
 4755                this.edit_with_autoindent(auto_indent_edits, cx);
 4756            }
 4757
 4758            let buffer = this.buffer.read(cx).snapshot(cx);
 4759            let new_selections = selection_info
 4760                .into_iter()
 4761                .map(|(extra_newline_inserted, new_selection)| {
 4762                    let mut cursor = new_selection.end.to_point(&buffer);
 4763                    if extra_newline_inserted {
 4764                        cursor.row -= 1;
 4765                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4766                    }
 4767                    new_selection.map(|_| cursor)
 4768                })
 4769                .collect();
 4770
 4771            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4772            this.refresh_edit_prediction(true, false, window, cx);
 4773        });
 4774    }
 4775
 4776    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4777        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4778
 4779        let buffer = self.buffer.read(cx);
 4780        let snapshot = buffer.snapshot(cx);
 4781
 4782        let mut edits = Vec::new();
 4783        let mut rows = Vec::new();
 4784
 4785        for (rows_inserted, selection) in self
 4786            .selections
 4787            .all_adjusted(&self.display_snapshot(cx))
 4788            .into_iter()
 4789            .enumerate()
 4790        {
 4791            let cursor = selection.head();
 4792            let row = cursor.row;
 4793
 4794            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4795
 4796            let newline = "\n".to_string();
 4797            edits.push((start_of_line..start_of_line, newline));
 4798
 4799            rows.push(row + rows_inserted as u32);
 4800        }
 4801
 4802        self.transact(window, cx, |editor, window, cx| {
 4803            editor.edit(edits, cx);
 4804
 4805            editor.change_selections(Default::default(), window, cx, |s| {
 4806                let mut index = 0;
 4807                s.move_cursors_with(|map, _, _| {
 4808                    let row = rows[index];
 4809                    index += 1;
 4810
 4811                    let point = Point::new(row, 0);
 4812                    let boundary = map.next_line_boundary(point).1;
 4813                    let clipped = map.clip_point(boundary, Bias::Left);
 4814
 4815                    (clipped, SelectionGoal::None)
 4816                });
 4817            });
 4818
 4819            let mut indent_edits = Vec::new();
 4820            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4821            for row in rows {
 4822                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4823                for (row, indent) in indents {
 4824                    if indent.len == 0 {
 4825                        continue;
 4826                    }
 4827
 4828                    let text = match indent.kind {
 4829                        IndentKind::Space => " ".repeat(indent.len as usize),
 4830                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4831                    };
 4832                    let point = Point::new(row.0, 0);
 4833                    indent_edits.push((point..point, text));
 4834                }
 4835            }
 4836            editor.edit(indent_edits, cx);
 4837        });
 4838    }
 4839
 4840    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4841        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4842
 4843        let buffer = self.buffer.read(cx);
 4844        let snapshot = buffer.snapshot(cx);
 4845
 4846        let mut edits = Vec::new();
 4847        let mut rows = Vec::new();
 4848        let mut rows_inserted = 0;
 4849
 4850        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4851            let cursor = selection.head();
 4852            let row = cursor.row;
 4853
 4854            let point = Point::new(row + 1, 0);
 4855            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4856
 4857            let newline = "\n".to_string();
 4858            edits.push((start_of_line..start_of_line, newline));
 4859
 4860            rows_inserted += 1;
 4861            rows.push(row + rows_inserted);
 4862        }
 4863
 4864        self.transact(window, cx, |editor, window, cx| {
 4865            editor.edit(edits, cx);
 4866
 4867            editor.change_selections(Default::default(), window, cx, |s| {
 4868                let mut index = 0;
 4869                s.move_cursors_with(|map, _, _| {
 4870                    let row = rows[index];
 4871                    index += 1;
 4872
 4873                    let point = Point::new(row, 0);
 4874                    let boundary = map.next_line_boundary(point).1;
 4875                    let clipped = map.clip_point(boundary, Bias::Left);
 4876
 4877                    (clipped, SelectionGoal::None)
 4878                });
 4879            });
 4880
 4881            let mut indent_edits = Vec::new();
 4882            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4883            for row in rows {
 4884                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4885                for (row, indent) in indents {
 4886                    if indent.len == 0 {
 4887                        continue;
 4888                    }
 4889
 4890                    let text = match indent.kind {
 4891                        IndentKind::Space => " ".repeat(indent.len as usize),
 4892                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4893                    };
 4894                    let point = Point::new(row.0, 0);
 4895                    indent_edits.push((point..point, text));
 4896                }
 4897            }
 4898            editor.edit(indent_edits, cx);
 4899        });
 4900    }
 4901
 4902    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4903        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4904            original_indent_columns: Vec::new(),
 4905        });
 4906        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4907    }
 4908
 4909    fn insert_with_autoindent_mode(
 4910        &mut self,
 4911        text: &str,
 4912        autoindent_mode: Option<AutoindentMode>,
 4913        window: &mut Window,
 4914        cx: &mut Context<Self>,
 4915    ) {
 4916        if self.read_only(cx) {
 4917            return;
 4918        }
 4919
 4920        let text: Arc<str> = text.into();
 4921        self.transact(window, cx, |this, window, cx| {
 4922            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 4923            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4924                let anchors = {
 4925                    let snapshot = buffer.read(cx);
 4926                    old_selections
 4927                        .iter()
 4928                        .map(|s| {
 4929                            let anchor = snapshot.anchor_after(s.head());
 4930                            s.map(|_| anchor)
 4931                        })
 4932                        .collect::<Vec<_>>()
 4933                };
 4934                buffer.edit(
 4935                    old_selections
 4936                        .iter()
 4937                        .map(|s| (s.start..s.end, text.clone())),
 4938                    autoindent_mode,
 4939                    cx,
 4940                );
 4941                anchors
 4942            });
 4943
 4944            this.change_selections(Default::default(), window, cx, |s| {
 4945                s.select_anchors(selection_anchors);
 4946            });
 4947
 4948            cx.notify();
 4949        });
 4950    }
 4951
 4952    fn trigger_completion_on_input(
 4953        &mut self,
 4954        text: &str,
 4955        trigger_in_words: bool,
 4956        window: &mut Window,
 4957        cx: &mut Context<Self>,
 4958    ) {
 4959        let completions_source = self
 4960            .context_menu
 4961            .borrow()
 4962            .as_ref()
 4963            .and_then(|menu| match menu {
 4964                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4965                CodeContextMenu::CodeActions(_) => None,
 4966            });
 4967
 4968        match completions_source {
 4969            Some(CompletionsMenuSource::Words { .. }) => {
 4970                self.open_or_update_completions_menu(
 4971                    Some(CompletionsMenuSource::Words {
 4972                        ignore_threshold: false,
 4973                    }),
 4974                    None,
 4975                    window,
 4976                    cx,
 4977                );
 4978            }
 4979            Some(CompletionsMenuSource::Normal)
 4980            | Some(CompletionsMenuSource::SnippetChoices)
 4981            | None
 4982                if self.is_completion_trigger(
 4983                    text,
 4984                    trigger_in_words,
 4985                    completions_source.is_some(),
 4986                    cx,
 4987                ) =>
 4988            {
 4989                self.show_completions(
 4990                    &ShowCompletions {
 4991                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4992                    },
 4993                    window,
 4994                    cx,
 4995                )
 4996            }
 4997            _ => {
 4998                self.hide_context_menu(window, cx);
 4999            }
 5000        }
 5001    }
 5002
 5003    fn is_completion_trigger(
 5004        &self,
 5005        text: &str,
 5006        trigger_in_words: bool,
 5007        menu_is_open: bool,
 5008        cx: &mut Context<Self>,
 5009    ) -> bool {
 5010        let position = self.selections.newest_anchor().head();
 5011        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 5012            return false;
 5013        };
 5014
 5015        if let Some(completion_provider) = &self.completion_provider {
 5016            completion_provider.is_completion_trigger(
 5017                &buffer,
 5018                position.text_anchor,
 5019                text,
 5020                trigger_in_words,
 5021                menu_is_open,
 5022                cx,
 5023            )
 5024        } else {
 5025            false
 5026        }
 5027    }
 5028
 5029    /// If any empty selections is touching the start of its innermost containing autoclose
 5030    /// region, expand it to select the brackets.
 5031    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5032        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5033        let buffer = self.buffer.read(cx).read(cx);
 5034        let new_selections = self
 5035            .selections_with_autoclose_regions(selections, &buffer)
 5036            .map(|(mut selection, region)| {
 5037                if !selection.is_empty() {
 5038                    return selection;
 5039                }
 5040
 5041                if let Some(region) = region {
 5042                    let mut range = region.range.to_offset(&buffer);
 5043                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5044                        range.start -= region.pair.start.len();
 5045                        if buffer.contains_str_at(range.start, &region.pair.start)
 5046                            && buffer.contains_str_at(range.end, &region.pair.end)
 5047                        {
 5048                            range.end += region.pair.end.len();
 5049                            selection.start = range.start;
 5050                            selection.end = range.end;
 5051
 5052                            return selection;
 5053                        }
 5054                    }
 5055                }
 5056
 5057                let always_treat_brackets_as_autoclosed = buffer
 5058                    .language_settings_at(selection.start, cx)
 5059                    .always_treat_brackets_as_autoclosed;
 5060
 5061                if !always_treat_brackets_as_autoclosed {
 5062                    return selection;
 5063                }
 5064
 5065                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5066                    for (pair, enabled) in scope.brackets() {
 5067                        if !enabled || !pair.close {
 5068                            continue;
 5069                        }
 5070
 5071                        if buffer.contains_str_at(selection.start, &pair.end) {
 5072                            let pair_start_len = pair.start.len();
 5073                            if buffer.contains_str_at(
 5074                                selection.start.saturating_sub(pair_start_len),
 5075                                &pair.start,
 5076                            ) {
 5077                                selection.start -= pair_start_len;
 5078                                selection.end += pair.end.len();
 5079
 5080                                return selection;
 5081                            }
 5082                        }
 5083                    }
 5084                }
 5085
 5086                selection
 5087            })
 5088            .collect();
 5089
 5090        drop(buffer);
 5091        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5092            selections.select(new_selections)
 5093        });
 5094    }
 5095
 5096    /// Iterate the given selections, and for each one, find the smallest surrounding
 5097    /// autoclose region. This uses the ordering of the selections and the autoclose
 5098    /// regions to avoid repeated comparisons.
 5099    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5100        &'a self,
 5101        selections: impl IntoIterator<Item = Selection<D>>,
 5102        buffer: &'a MultiBufferSnapshot,
 5103    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5104        let mut i = 0;
 5105        let mut regions = self.autoclose_regions.as_slice();
 5106        selections.into_iter().map(move |selection| {
 5107            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5108
 5109            let mut enclosing = None;
 5110            while let Some(pair_state) = regions.get(i) {
 5111                if pair_state.range.end.to_offset(buffer) < range.start {
 5112                    regions = &regions[i + 1..];
 5113                    i = 0;
 5114                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5115                    break;
 5116                } else {
 5117                    if pair_state.selection_id == selection.id {
 5118                        enclosing = Some(pair_state);
 5119                    }
 5120                    i += 1;
 5121                }
 5122            }
 5123
 5124            (selection, enclosing)
 5125        })
 5126    }
 5127
 5128    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5129    fn invalidate_autoclose_regions(
 5130        &mut self,
 5131        mut selections: &[Selection<Anchor>],
 5132        buffer: &MultiBufferSnapshot,
 5133    ) {
 5134        self.autoclose_regions.retain(|state| {
 5135            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5136                return false;
 5137            }
 5138
 5139            let mut i = 0;
 5140            while let Some(selection) = selections.get(i) {
 5141                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5142                    selections = &selections[1..];
 5143                    continue;
 5144                }
 5145                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5146                    break;
 5147                }
 5148                if selection.id == state.selection_id {
 5149                    return true;
 5150                } else {
 5151                    i += 1;
 5152                }
 5153            }
 5154            false
 5155        });
 5156    }
 5157
 5158    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5159        let offset = position.to_offset(buffer);
 5160        let (word_range, kind) =
 5161            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5162        if offset > word_range.start && kind == Some(CharKind::Word) {
 5163            Some(
 5164                buffer
 5165                    .text_for_range(word_range.start..offset)
 5166                    .collect::<String>(),
 5167            )
 5168        } else {
 5169            None
 5170        }
 5171    }
 5172
 5173    pub fn visible_excerpts(
 5174        &self,
 5175        cx: &mut Context<Editor>,
 5176    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5177        let Some(project) = self.project() else {
 5178            return HashMap::default();
 5179        };
 5180        let project = project.read(cx);
 5181        let multi_buffer = self.buffer().read(cx);
 5182        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5183        let multi_buffer_visible_start = self
 5184            .scroll_manager
 5185            .anchor()
 5186            .anchor
 5187            .to_point(&multi_buffer_snapshot);
 5188        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5189            multi_buffer_visible_start
 5190                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5191            Bias::Left,
 5192        );
 5193        multi_buffer_snapshot
 5194            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5195            .into_iter()
 5196            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5197            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5198                let buffer_file = project::File::from_dyn(buffer.file())?;
 5199                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5200                let worktree_entry = buffer_worktree
 5201                    .read(cx)
 5202                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5203                if worktree_entry.is_ignored {
 5204                    None
 5205                } else {
 5206                    Some((
 5207                        excerpt_id,
 5208                        (
 5209                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5210                            buffer.version().clone(),
 5211                            excerpt_visible_range,
 5212                        ),
 5213                    ))
 5214                }
 5215            })
 5216            .collect()
 5217    }
 5218
 5219    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5220        TextLayoutDetails {
 5221            text_system: window.text_system().clone(),
 5222            editor_style: self.style.clone().unwrap(),
 5223            rem_size: window.rem_size(),
 5224            scroll_anchor: self.scroll_manager.anchor(),
 5225            visible_rows: self.visible_line_count(),
 5226            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5227        }
 5228    }
 5229
 5230    fn trigger_on_type_formatting(
 5231        &self,
 5232        input: String,
 5233        window: &mut Window,
 5234        cx: &mut Context<Self>,
 5235    ) -> Option<Task<Result<()>>> {
 5236        if input.len() != 1 {
 5237            return None;
 5238        }
 5239
 5240        let project = self.project()?;
 5241        let position = self.selections.newest_anchor().head();
 5242        let (buffer, buffer_position) = self
 5243            .buffer
 5244            .read(cx)
 5245            .text_anchor_for_position(position, cx)?;
 5246
 5247        let settings = language_settings::language_settings(
 5248            buffer
 5249                .read(cx)
 5250                .language_at(buffer_position)
 5251                .map(|l| l.name()),
 5252            buffer.read(cx).file(),
 5253            cx,
 5254        );
 5255        if !settings.use_on_type_format {
 5256            return None;
 5257        }
 5258
 5259        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5260        // hence we do LSP request & edit on host side only — add formats to host's history.
 5261        let push_to_lsp_host_history = true;
 5262        // If this is not the host, append its history with new edits.
 5263        let push_to_client_history = project.read(cx).is_via_collab();
 5264
 5265        let on_type_formatting = project.update(cx, |project, cx| {
 5266            project.on_type_format(
 5267                buffer.clone(),
 5268                buffer_position,
 5269                input,
 5270                push_to_lsp_host_history,
 5271                cx,
 5272            )
 5273        });
 5274        Some(cx.spawn_in(window, async move |editor, cx| {
 5275            if let Some(transaction) = on_type_formatting.await? {
 5276                if push_to_client_history {
 5277                    buffer
 5278                        .update(cx, |buffer, _| {
 5279                            buffer.push_transaction(transaction, Instant::now());
 5280                            buffer.finalize_last_transaction();
 5281                        })
 5282                        .ok();
 5283                }
 5284                editor.update(cx, |editor, cx| {
 5285                    editor.refresh_document_highlights(cx);
 5286                })?;
 5287            }
 5288            Ok(())
 5289        }))
 5290    }
 5291
 5292    pub fn show_word_completions(
 5293        &mut self,
 5294        _: &ShowWordCompletions,
 5295        window: &mut Window,
 5296        cx: &mut Context<Self>,
 5297    ) {
 5298        self.open_or_update_completions_menu(
 5299            Some(CompletionsMenuSource::Words {
 5300                ignore_threshold: true,
 5301            }),
 5302            None,
 5303            window,
 5304            cx,
 5305        );
 5306    }
 5307
 5308    pub fn show_completions(
 5309        &mut self,
 5310        options: &ShowCompletions,
 5311        window: &mut Window,
 5312        cx: &mut Context<Self>,
 5313    ) {
 5314        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5315    }
 5316
 5317    fn open_or_update_completions_menu(
 5318        &mut self,
 5319        requested_source: Option<CompletionsMenuSource>,
 5320        trigger: Option<&str>,
 5321        window: &mut Window,
 5322        cx: &mut Context<Self>,
 5323    ) {
 5324        if self.pending_rename.is_some() {
 5325            return;
 5326        }
 5327
 5328        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5329
 5330        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5331        // inserted and selected. To handle that case, the start of the selection is used so that
 5332        // the menu starts with all choices.
 5333        let position = self
 5334            .selections
 5335            .newest_anchor()
 5336            .start
 5337            .bias_right(&multibuffer_snapshot);
 5338        if position.diff_base_anchor.is_some() {
 5339            return;
 5340        }
 5341        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5342        let Some(buffer) = buffer_position
 5343            .buffer_id
 5344            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5345        else {
 5346            return;
 5347        };
 5348        let buffer_snapshot = buffer.read(cx).snapshot();
 5349
 5350        let query: Option<Arc<String>> =
 5351            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5352                .map(|query| query.into());
 5353
 5354        drop(multibuffer_snapshot);
 5355
 5356        // Hide the current completions menu when query is empty. Without this, cached
 5357        // completions from before the trigger char may be reused (#32774).
 5358        if query.is_none() {
 5359            let menu_is_open = matches!(
 5360                self.context_menu.borrow().as_ref(),
 5361                Some(CodeContextMenu::Completions(_))
 5362            );
 5363            if menu_is_open {
 5364                self.hide_context_menu(window, cx);
 5365            }
 5366        }
 5367
 5368        let mut ignore_word_threshold = false;
 5369        let provider = match requested_source {
 5370            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5371            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5372                ignore_word_threshold = ignore_threshold;
 5373                None
 5374            }
 5375            Some(CompletionsMenuSource::SnippetChoices) => {
 5376                log::error!("bug: SnippetChoices requested_source is not handled");
 5377                None
 5378            }
 5379        };
 5380
 5381        let sort_completions = provider
 5382            .as_ref()
 5383            .is_some_and(|provider| provider.sort_completions());
 5384
 5385        let filter_completions = provider
 5386            .as_ref()
 5387            .is_none_or(|provider| provider.filter_completions());
 5388
 5389        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5390            if filter_completions {
 5391                menu.filter(query.clone(), provider.clone(), window, cx);
 5392            }
 5393            // When `is_incomplete` is false, no need to re-query completions when the current query
 5394            // is a suffix of the initial query.
 5395            if !menu.is_incomplete {
 5396                // If the new query is a suffix of the old query (typing more characters) and
 5397                // the previous result was complete, the existing completions can be filtered.
 5398                //
 5399                // Note that this is always true for snippet completions.
 5400                let query_matches = match (&menu.initial_query, &query) {
 5401                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5402                    (None, _) => true,
 5403                    _ => false,
 5404                };
 5405                if query_matches {
 5406                    let position_matches = if menu.initial_position == position {
 5407                        true
 5408                    } else {
 5409                        let snapshot = self.buffer.read(cx).read(cx);
 5410                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5411                    };
 5412                    if position_matches {
 5413                        return;
 5414                    }
 5415                }
 5416            }
 5417        };
 5418
 5419        let trigger_kind = match trigger {
 5420            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5421                CompletionTriggerKind::TRIGGER_CHARACTER
 5422            }
 5423            _ => CompletionTriggerKind::INVOKED,
 5424        };
 5425        let completion_context = CompletionContext {
 5426            trigger_character: trigger.and_then(|trigger| {
 5427                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5428                    Some(String::from(trigger))
 5429                } else {
 5430                    None
 5431                }
 5432            }),
 5433            trigger_kind,
 5434        };
 5435
 5436        let Anchor {
 5437            excerpt_id: buffer_excerpt_id,
 5438            text_anchor: buffer_position,
 5439            ..
 5440        } = buffer_position;
 5441
 5442        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5443            buffer_snapshot.surrounding_word(buffer_position, None)
 5444        {
 5445            let word_to_exclude = buffer_snapshot
 5446                .text_for_range(word_range.clone())
 5447                .collect::<String>();
 5448            (
 5449                buffer_snapshot.anchor_before(word_range.start)
 5450                    ..buffer_snapshot.anchor_after(buffer_position),
 5451                Some(word_to_exclude),
 5452            )
 5453        } else {
 5454            (buffer_position..buffer_position, None)
 5455        };
 5456
 5457        let language = buffer_snapshot
 5458            .language_at(buffer_position)
 5459            .map(|language| language.name());
 5460
 5461        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5462            .completions
 5463            .clone();
 5464
 5465        let show_completion_documentation = buffer_snapshot
 5466            .settings_at(buffer_position, cx)
 5467            .show_completion_documentation;
 5468
 5469        // The document can be large, so stay in reasonable bounds when searching for words,
 5470        // otherwise completion pop-up might be slow to appear.
 5471        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5472        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5473        let min_word_search = buffer_snapshot.clip_point(
 5474            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5475            Bias::Left,
 5476        );
 5477        let max_word_search = buffer_snapshot.clip_point(
 5478            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5479            Bias::Right,
 5480        );
 5481        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5482            ..buffer_snapshot.point_to_offset(max_word_search);
 5483
 5484        let skip_digits = query
 5485            .as_ref()
 5486            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5487
 5488        let omit_word_completions = !self.word_completions_enabled
 5489            || (!ignore_word_threshold
 5490                && match &query {
 5491                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5492                    None => completion_settings.words_min_length != 0,
 5493                });
 5494
 5495        let (mut words, provider_responses) = match &provider {
 5496            Some(provider) => {
 5497                let provider_responses = provider.completions(
 5498                    buffer_excerpt_id,
 5499                    &buffer,
 5500                    buffer_position,
 5501                    completion_context,
 5502                    window,
 5503                    cx,
 5504                );
 5505
 5506                let words = match (omit_word_completions, completion_settings.words) {
 5507                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5508                        Task::ready(BTreeMap::default())
 5509                    }
 5510                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5511                        .background_spawn(async move {
 5512                            buffer_snapshot.words_in_range(WordsQuery {
 5513                                fuzzy_contents: None,
 5514                                range: word_search_range,
 5515                                skip_digits,
 5516                            })
 5517                        }),
 5518                };
 5519
 5520                (words, provider_responses)
 5521            }
 5522            None => {
 5523                let words = if omit_word_completions {
 5524                    Task::ready(BTreeMap::default())
 5525                } else {
 5526                    cx.background_spawn(async move {
 5527                        buffer_snapshot.words_in_range(WordsQuery {
 5528                            fuzzy_contents: None,
 5529                            range: word_search_range,
 5530                            skip_digits,
 5531                        })
 5532                    })
 5533                };
 5534                (words, Task::ready(Ok(Vec::new())))
 5535            }
 5536        };
 5537
 5538        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5539
 5540        let id = post_inc(&mut self.next_completion_id);
 5541        let task = cx.spawn_in(window, async move |editor, cx| {
 5542            let Ok(()) = editor.update(cx, |this, _| {
 5543                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5544            }) else {
 5545                return;
 5546            };
 5547
 5548            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5549            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5550            let mut completions = Vec::new();
 5551            let mut is_incomplete = false;
 5552            let mut display_options: Option<CompletionDisplayOptions> = None;
 5553            if let Some(provider_responses) = provider_responses.await.log_err()
 5554                && !provider_responses.is_empty()
 5555            {
 5556                for response in provider_responses {
 5557                    completions.extend(response.completions);
 5558                    is_incomplete = is_incomplete || response.is_incomplete;
 5559                    match display_options.as_mut() {
 5560                        None => {
 5561                            display_options = Some(response.display_options);
 5562                        }
 5563                        Some(options) => options.merge(&response.display_options),
 5564                    }
 5565                }
 5566                if completion_settings.words == WordsCompletionMode::Fallback {
 5567                    words = Task::ready(BTreeMap::default());
 5568                }
 5569            }
 5570            let display_options = display_options.unwrap_or_default();
 5571
 5572            let mut words = words.await;
 5573            if let Some(word_to_exclude) = &word_to_exclude {
 5574                words.remove(word_to_exclude);
 5575            }
 5576            for lsp_completion in &completions {
 5577                words.remove(&lsp_completion.new_text);
 5578            }
 5579            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5580                replace_range: word_replace_range.clone(),
 5581                new_text: word.clone(),
 5582                label: CodeLabel::plain(word, None),
 5583                icon_path: None,
 5584                documentation: None,
 5585                source: CompletionSource::BufferWord {
 5586                    word_range,
 5587                    resolved: false,
 5588                },
 5589                insert_text_mode: Some(InsertTextMode::AS_IS),
 5590                confirm: None,
 5591            }));
 5592
 5593            let menu = if completions.is_empty() {
 5594                None
 5595            } else {
 5596                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5597                    let languages = editor
 5598                        .workspace
 5599                        .as_ref()
 5600                        .and_then(|(workspace, _)| workspace.upgrade())
 5601                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5602                    let menu = CompletionsMenu::new(
 5603                        id,
 5604                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5605                        sort_completions,
 5606                        show_completion_documentation,
 5607                        position,
 5608                        query.clone(),
 5609                        is_incomplete,
 5610                        buffer.clone(),
 5611                        completions.into(),
 5612                        display_options,
 5613                        snippet_sort_order,
 5614                        languages,
 5615                        language,
 5616                        cx,
 5617                    );
 5618
 5619                    let query = if filter_completions { query } else { None };
 5620                    let matches_task = if let Some(query) = query {
 5621                        menu.do_async_filtering(query, cx)
 5622                    } else {
 5623                        Task::ready(menu.unfiltered_matches())
 5624                    };
 5625                    (menu, matches_task)
 5626                }) else {
 5627                    return;
 5628                };
 5629
 5630                let matches = matches_task.await;
 5631
 5632                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5633                    // Newer menu already set, so exit.
 5634                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5635                        editor.context_menu.borrow().as_ref()
 5636                        && prev_menu.id > id
 5637                    {
 5638                        return;
 5639                    };
 5640
 5641                    // Only valid to take prev_menu because it the new menu is immediately set
 5642                    // below, or the menu is hidden.
 5643                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5644                        editor.context_menu.borrow_mut().take()
 5645                    {
 5646                        let position_matches =
 5647                            if prev_menu.initial_position == menu.initial_position {
 5648                                true
 5649                            } else {
 5650                                let snapshot = editor.buffer.read(cx).read(cx);
 5651                                prev_menu.initial_position.to_offset(&snapshot)
 5652                                    == menu.initial_position.to_offset(&snapshot)
 5653                            };
 5654                        if position_matches {
 5655                            // Preserve markdown cache before `set_filter_results` because it will
 5656                            // try to populate the documentation cache.
 5657                            menu.preserve_markdown_cache(prev_menu);
 5658                        }
 5659                    };
 5660
 5661                    menu.set_filter_results(matches, provider, window, cx);
 5662                }) else {
 5663                    return;
 5664                };
 5665
 5666                menu.visible().then_some(menu)
 5667            };
 5668
 5669            editor
 5670                .update_in(cx, |editor, window, cx| {
 5671                    if editor.focus_handle.is_focused(window)
 5672                        && let Some(menu) = menu
 5673                    {
 5674                        *editor.context_menu.borrow_mut() =
 5675                            Some(CodeContextMenu::Completions(menu));
 5676
 5677                        crate::hover_popover::hide_hover(editor, cx);
 5678                        if editor.show_edit_predictions_in_menu() {
 5679                            editor.update_visible_edit_prediction(window, cx);
 5680                        } else {
 5681                            editor.discard_edit_prediction(false, cx);
 5682                        }
 5683
 5684                        cx.notify();
 5685                        return;
 5686                    }
 5687
 5688                    if editor.completion_tasks.len() <= 1 {
 5689                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5690                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5691                        // If it was already hidden and we don't show edit predictions in the menu,
 5692                        // we should also show the edit prediction when available.
 5693                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5694                            editor.update_visible_edit_prediction(window, cx);
 5695                        }
 5696                    }
 5697                })
 5698                .ok();
 5699        });
 5700
 5701        self.completion_tasks.push((id, task));
 5702    }
 5703
 5704    #[cfg(feature = "test-support")]
 5705    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5706        let menu = self.context_menu.borrow();
 5707        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5708            let completions = menu.completions.borrow();
 5709            Some(completions.to_vec())
 5710        } else {
 5711            None
 5712        }
 5713    }
 5714
 5715    pub fn with_completions_menu_matching_id<R>(
 5716        &self,
 5717        id: CompletionId,
 5718        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5719    ) -> R {
 5720        let mut context_menu = self.context_menu.borrow_mut();
 5721        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5722            return f(None);
 5723        };
 5724        if completions_menu.id != id {
 5725            return f(None);
 5726        }
 5727        f(Some(completions_menu))
 5728    }
 5729
 5730    pub fn confirm_completion(
 5731        &mut self,
 5732        action: &ConfirmCompletion,
 5733        window: &mut Window,
 5734        cx: &mut Context<Self>,
 5735    ) -> Option<Task<Result<()>>> {
 5736        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5737        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5738    }
 5739
 5740    pub fn confirm_completion_insert(
 5741        &mut self,
 5742        _: &ConfirmCompletionInsert,
 5743        window: &mut Window,
 5744        cx: &mut Context<Self>,
 5745    ) -> Option<Task<Result<()>>> {
 5746        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5747        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5748    }
 5749
 5750    pub fn confirm_completion_replace(
 5751        &mut self,
 5752        _: &ConfirmCompletionReplace,
 5753        window: &mut Window,
 5754        cx: &mut Context<Self>,
 5755    ) -> Option<Task<Result<()>>> {
 5756        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5757        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5758    }
 5759
 5760    pub fn compose_completion(
 5761        &mut self,
 5762        action: &ComposeCompletion,
 5763        window: &mut Window,
 5764        cx: &mut Context<Self>,
 5765    ) -> Option<Task<Result<()>>> {
 5766        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5767        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5768    }
 5769
 5770    fn do_completion(
 5771        &mut self,
 5772        item_ix: Option<usize>,
 5773        intent: CompletionIntent,
 5774        window: &mut Window,
 5775        cx: &mut Context<Editor>,
 5776    ) -> Option<Task<Result<()>>> {
 5777        use language::ToOffset as _;
 5778
 5779        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5780        else {
 5781            return None;
 5782        };
 5783
 5784        let candidate_id = {
 5785            let entries = completions_menu.entries.borrow();
 5786            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5787            if self.show_edit_predictions_in_menu() {
 5788                self.discard_edit_prediction(true, cx);
 5789            }
 5790            mat.candidate_id
 5791        };
 5792
 5793        let completion = completions_menu
 5794            .completions
 5795            .borrow()
 5796            .get(candidate_id)?
 5797            .clone();
 5798        cx.stop_propagation();
 5799
 5800        let buffer_handle = completions_menu.buffer.clone();
 5801
 5802        let CompletionEdit {
 5803            new_text,
 5804            snippet,
 5805            replace_range,
 5806        } = process_completion_for_edit(
 5807            &completion,
 5808            intent,
 5809            &buffer_handle,
 5810            &completions_menu.initial_position.text_anchor,
 5811            cx,
 5812        );
 5813
 5814        let buffer = buffer_handle.read(cx);
 5815        let snapshot = self.buffer.read(cx).snapshot(cx);
 5816        let newest_anchor = self.selections.newest_anchor();
 5817        let replace_range_multibuffer = {
 5818            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5819            excerpt.map_range_from_buffer(replace_range.clone())
 5820        };
 5821        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5822            return None;
 5823        }
 5824
 5825        let old_text = buffer
 5826            .text_for_range(replace_range.clone())
 5827            .collect::<String>();
 5828        let lookbehind = newest_anchor
 5829            .start
 5830            .text_anchor
 5831            .to_offset(buffer)
 5832            .saturating_sub(replace_range.start);
 5833        let lookahead = replace_range
 5834            .end
 5835            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5836        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5837        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5838
 5839        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5840        let mut ranges = Vec::new();
 5841        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5842
 5843        for selection in &selections {
 5844            let range = if selection.id == newest_anchor.id {
 5845                replace_range_multibuffer.clone()
 5846            } else {
 5847                let mut range = selection.range();
 5848
 5849                // if prefix is present, don't duplicate it
 5850                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5851                    range.start = range.start.saturating_sub(lookbehind);
 5852
 5853                    // if suffix is also present, mimic the newest cursor and replace it
 5854                    if selection.id != newest_anchor.id
 5855                        && snapshot.contains_str_at(range.end, suffix)
 5856                    {
 5857                        range.end += lookahead;
 5858                    }
 5859                }
 5860                range
 5861            };
 5862
 5863            ranges.push(range.clone());
 5864
 5865            if !self.linked_edit_ranges.is_empty() {
 5866                let start_anchor = snapshot.anchor_before(range.start);
 5867                let end_anchor = snapshot.anchor_after(range.end);
 5868                if let Some(ranges) = self
 5869                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5870                {
 5871                    for (buffer, edits) in ranges {
 5872                        linked_edits
 5873                            .entry(buffer.clone())
 5874                            .or_default()
 5875                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5876                    }
 5877                }
 5878            }
 5879        }
 5880
 5881        let common_prefix_len = old_text
 5882            .chars()
 5883            .zip(new_text.chars())
 5884            .take_while(|(a, b)| a == b)
 5885            .map(|(a, _)| a.len_utf8())
 5886            .sum::<usize>();
 5887
 5888        cx.emit(EditorEvent::InputHandled {
 5889            utf16_range_to_replace: None,
 5890            text: new_text[common_prefix_len..].into(),
 5891        });
 5892
 5893        self.transact(window, cx, |editor, window, cx| {
 5894            if let Some(mut snippet) = snippet {
 5895                snippet.text = new_text.to_string();
 5896                editor
 5897                    .insert_snippet(&ranges, snippet, window, cx)
 5898                    .log_err();
 5899            } else {
 5900                editor.buffer.update(cx, |multi_buffer, cx| {
 5901                    let auto_indent = match completion.insert_text_mode {
 5902                        Some(InsertTextMode::AS_IS) => None,
 5903                        _ => editor.autoindent_mode.clone(),
 5904                    };
 5905                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5906                    multi_buffer.edit(edits, auto_indent, cx);
 5907                });
 5908            }
 5909            for (buffer, edits) in linked_edits {
 5910                buffer.update(cx, |buffer, cx| {
 5911                    let snapshot = buffer.snapshot();
 5912                    let edits = edits
 5913                        .into_iter()
 5914                        .map(|(range, text)| {
 5915                            use text::ToPoint as TP;
 5916                            let end_point = TP::to_point(&range.end, &snapshot);
 5917                            let start_point = TP::to_point(&range.start, &snapshot);
 5918                            (start_point..end_point, text)
 5919                        })
 5920                        .sorted_by_key(|(range, _)| range.start);
 5921                    buffer.edit(edits, None, cx);
 5922                })
 5923            }
 5924
 5925            editor.refresh_edit_prediction(true, false, window, cx);
 5926        });
 5927        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 5928
 5929        let show_new_completions_on_confirm = completion
 5930            .confirm
 5931            .as_ref()
 5932            .is_some_and(|confirm| confirm(intent, window, cx));
 5933        if show_new_completions_on_confirm {
 5934            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5935        }
 5936
 5937        let provider = self.completion_provider.as_ref()?;
 5938        drop(completion);
 5939        let apply_edits = provider.apply_additional_edits_for_completion(
 5940            buffer_handle,
 5941            completions_menu.completions.clone(),
 5942            candidate_id,
 5943            true,
 5944            cx,
 5945        );
 5946
 5947        let editor_settings = EditorSettings::get_global(cx);
 5948        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5949            // After the code completion is finished, users often want to know what signatures are needed.
 5950            // so we should automatically call signature_help
 5951            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5952        }
 5953
 5954        Some(cx.foreground_executor().spawn(async move {
 5955            apply_edits.await?;
 5956            Ok(())
 5957        }))
 5958    }
 5959
 5960    pub fn toggle_code_actions(
 5961        &mut self,
 5962        action: &ToggleCodeActions,
 5963        window: &mut Window,
 5964        cx: &mut Context<Self>,
 5965    ) {
 5966        let quick_launch = action.quick_launch;
 5967        let mut context_menu = self.context_menu.borrow_mut();
 5968        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5969            if code_actions.deployed_from == action.deployed_from {
 5970                // Toggle if we're selecting the same one
 5971                *context_menu = None;
 5972                cx.notify();
 5973                return;
 5974            } else {
 5975                // Otherwise, clear it and start a new one
 5976                *context_menu = None;
 5977                cx.notify();
 5978            }
 5979        }
 5980        drop(context_menu);
 5981        let snapshot = self.snapshot(window, cx);
 5982        let deployed_from = action.deployed_from.clone();
 5983        let action = action.clone();
 5984        self.completion_tasks.clear();
 5985        self.discard_edit_prediction(false, cx);
 5986
 5987        let multibuffer_point = match &action.deployed_from {
 5988            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5989                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5990            }
 5991            _ => self
 5992                .selections
 5993                .newest::<Point>(&snapshot.display_snapshot)
 5994                .head(),
 5995        };
 5996        let Some((buffer, buffer_row)) = snapshot
 5997            .buffer_snapshot()
 5998            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5999            .and_then(|(buffer_snapshot, range)| {
 6000                self.buffer()
 6001                    .read(cx)
 6002                    .buffer(buffer_snapshot.remote_id())
 6003                    .map(|buffer| (buffer, range.start.row))
 6004            })
 6005        else {
 6006            return;
 6007        };
 6008        let buffer_id = buffer.read(cx).remote_id();
 6009        let tasks = self
 6010            .tasks
 6011            .get(&(buffer_id, buffer_row))
 6012            .map(|t| Arc::new(t.to_owned()));
 6013
 6014        if !self.focus_handle.is_focused(window) {
 6015            return;
 6016        }
 6017        let project = self.project.clone();
 6018
 6019        let code_actions_task = match deployed_from {
 6020            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6021            _ => self.code_actions(buffer_row, window, cx),
 6022        };
 6023
 6024        let runnable_task = match deployed_from {
 6025            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6026            _ => {
 6027                let mut task_context_task = Task::ready(None);
 6028                if let Some(tasks) = &tasks
 6029                    && let Some(project) = project
 6030                {
 6031                    task_context_task =
 6032                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6033                }
 6034
 6035                cx.spawn_in(window, {
 6036                    let buffer = buffer.clone();
 6037                    async move |editor, cx| {
 6038                        let task_context = task_context_task.await;
 6039
 6040                        let resolved_tasks =
 6041                            tasks
 6042                                .zip(task_context.clone())
 6043                                .map(|(tasks, task_context)| ResolvedTasks {
 6044                                    templates: tasks.resolve(&task_context).collect(),
 6045                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6046                                        multibuffer_point.row,
 6047                                        tasks.column,
 6048                                    )),
 6049                                });
 6050                        let debug_scenarios = editor
 6051                            .update(cx, |editor, cx| {
 6052                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6053                            })?
 6054                            .await;
 6055                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6056                    }
 6057                })
 6058            }
 6059        };
 6060
 6061        cx.spawn_in(window, async move |editor, cx| {
 6062            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6063            let code_actions = code_actions_task.await;
 6064            let spawn_straight_away = quick_launch
 6065                && resolved_tasks
 6066                    .as_ref()
 6067                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6068                && code_actions
 6069                    .as_ref()
 6070                    .is_none_or(|actions| actions.is_empty())
 6071                && debug_scenarios.is_empty();
 6072
 6073            editor.update_in(cx, |editor, window, cx| {
 6074                crate::hover_popover::hide_hover(editor, cx);
 6075                let actions = CodeActionContents::new(
 6076                    resolved_tasks,
 6077                    code_actions,
 6078                    debug_scenarios,
 6079                    task_context.unwrap_or_default(),
 6080                );
 6081
 6082                // Don't show the menu if there are no actions available
 6083                if actions.is_empty() {
 6084                    cx.notify();
 6085                    return Task::ready(Ok(()));
 6086                }
 6087
 6088                *editor.context_menu.borrow_mut() =
 6089                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6090                        buffer,
 6091                        actions,
 6092                        selected_item: Default::default(),
 6093                        scroll_handle: UniformListScrollHandle::default(),
 6094                        deployed_from,
 6095                    }));
 6096                cx.notify();
 6097                if spawn_straight_away
 6098                    && let Some(task) = editor.confirm_code_action(
 6099                        &ConfirmCodeAction { item_ix: Some(0) },
 6100                        window,
 6101                        cx,
 6102                    )
 6103                {
 6104                    return task;
 6105                }
 6106
 6107                Task::ready(Ok(()))
 6108            })
 6109        })
 6110        .detach_and_log_err(cx);
 6111    }
 6112
 6113    fn debug_scenarios(
 6114        &mut self,
 6115        resolved_tasks: &Option<ResolvedTasks>,
 6116        buffer: &Entity<Buffer>,
 6117        cx: &mut App,
 6118    ) -> Task<Vec<task::DebugScenario>> {
 6119        maybe!({
 6120            let project = self.project()?;
 6121            let dap_store = project.read(cx).dap_store();
 6122            let mut scenarios = vec![];
 6123            let resolved_tasks = resolved_tasks.as_ref()?;
 6124            let buffer = buffer.read(cx);
 6125            let language = buffer.language()?;
 6126            let file = buffer.file();
 6127            let debug_adapter = language_settings(language.name().into(), file, cx)
 6128                .debuggers
 6129                .first()
 6130                .map(SharedString::from)
 6131                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6132
 6133            dap_store.update(cx, |dap_store, cx| {
 6134                for (_, task) in &resolved_tasks.templates {
 6135                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6136                        task.original_task().clone(),
 6137                        debug_adapter.clone().into(),
 6138                        task.display_label().to_owned().into(),
 6139                        cx,
 6140                    );
 6141                    scenarios.push(maybe_scenario);
 6142                }
 6143            });
 6144            Some(cx.background_spawn(async move {
 6145                futures::future::join_all(scenarios)
 6146                    .await
 6147                    .into_iter()
 6148                    .flatten()
 6149                    .collect::<Vec<_>>()
 6150            }))
 6151        })
 6152        .unwrap_or_else(|| Task::ready(vec![]))
 6153    }
 6154
 6155    fn code_actions(
 6156        &mut self,
 6157        buffer_row: u32,
 6158        window: &mut Window,
 6159        cx: &mut Context<Self>,
 6160    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6161        let mut task = self.code_actions_task.take();
 6162        cx.spawn_in(window, async move |editor, cx| {
 6163            while let Some(prev_task) = task {
 6164                prev_task.await.log_err();
 6165                task = editor
 6166                    .update(cx, |this, _| this.code_actions_task.take())
 6167                    .ok()?;
 6168            }
 6169
 6170            editor
 6171                .update(cx, |editor, cx| {
 6172                    editor
 6173                        .available_code_actions
 6174                        .clone()
 6175                        .and_then(|(location, code_actions)| {
 6176                            let snapshot = location.buffer.read(cx).snapshot();
 6177                            let point_range = location.range.to_point(&snapshot);
 6178                            let point_range = point_range.start.row..=point_range.end.row;
 6179                            if point_range.contains(&buffer_row) {
 6180                                Some(code_actions)
 6181                            } else {
 6182                                None
 6183                            }
 6184                        })
 6185                })
 6186                .ok()
 6187                .flatten()
 6188        })
 6189    }
 6190
 6191    pub fn confirm_code_action(
 6192        &mut self,
 6193        action: &ConfirmCodeAction,
 6194        window: &mut Window,
 6195        cx: &mut Context<Self>,
 6196    ) -> Option<Task<Result<()>>> {
 6197        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6198
 6199        let actions_menu =
 6200            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6201                menu
 6202            } else {
 6203                return None;
 6204            };
 6205
 6206        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6207        let action = actions_menu.actions.get(action_ix)?;
 6208        let title = action.label();
 6209        let buffer = actions_menu.buffer;
 6210        let workspace = self.workspace()?;
 6211
 6212        match action {
 6213            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6214                workspace.update(cx, |workspace, cx| {
 6215                    workspace.schedule_resolved_task(
 6216                        task_source_kind,
 6217                        resolved_task,
 6218                        false,
 6219                        window,
 6220                        cx,
 6221                    );
 6222
 6223                    Some(Task::ready(Ok(())))
 6224                })
 6225            }
 6226            CodeActionsItem::CodeAction {
 6227                excerpt_id,
 6228                action,
 6229                provider,
 6230            } => {
 6231                let apply_code_action =
 6232                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6233                let workspace = workspace.downgrade();
 6234                Some(cx.spawn_in(window, async move |editor, cx| {
 6235                    let project_transaction = apply_code_action.await?;
 6236                    Self::open_project_transaction(
 6237                        &editor,
 6238                        workspace,
 6239                        project_transaction,
 6240                        title,
 6241                        cx,
 6242                    )
 6243                    .await
 6244                }))
 6245            }
 6246            CodeActionsItem::DebugScenario(scenario) => {
 6247                let context = actions_menu.actions.context;
 6248
 6249                workspace.update(cx, |workspace, cx| {
 6250                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6251                    workspace.start_debug_session(
 6252                        scenario,
 6253                        context,
 6254                        Some(buffer),
 6255                        None,
 6256                        window,
 6257                        cx,
 6258                    );
 6259                });
 6260                Some(Task::ready(Ok(())))
 6261            }
 6262        }
 6263    }
 6264
 6265    pub async fn open_project_transaction(
 6266        editor: &WeakEntity<Editor>,
 6267        workspace: WeakEntity<Workspace>,
 6268        transaction: ProjectTransaction,
 6269        title: String,
 6270        cx: &mut AsyncWindowContext,
 6271    ) -> Result<()> {
 6272        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6273        cx.update(|_, cx| {
 6274            entries.sort_unstable_by_key(|(buffer, _)| {
 6275                buffer.read(cx).file().map(|f| f.path().clone())
 6276            });
 6277        })?;
 6278        if entries.is_empty() {
 6279            return Ok(());
 6280        }
 6281
 6282        // If the project transaction's edits are all contained within this editor, then
 6283        // avoid opening a new editor to display them.
 6284
 6285        if let [(buffer, transaction)] = &*entries {
 6286            let excerpt = editor.update(cx, |editor, cx| {
 6287                editor
 6288                    .buffer()
 6289                    .read(cx)
 6290                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6291            })?;
 6292            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6293                && excerpted_buffer == *buffer
 6294            {
 6295                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6296                    let excerpt_range = excerpt_range.to_offset(buffer);
 6297                    buffer
 6298                        .edited_ranges_for_transaction::<usize>(transaction)
 6299                        .all(|range| {
 6300                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6301                        })
 6302                })?;
 6303
 6304                if all_edits_within_excerpt {
 6305                    return Ok(());
 6306                }
 6307            }
 6308        }
 6309
 6310        let mut ranges_to_highlight = Vec::new();
 6311        let excerpt_buffer = cx.new(|cx| {
 6312            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6313            for (buffer_handle, transaction) in &entries {
 6314                let edited_ranges = buffer_handle
 6315                    .read(cx)
 6316                    .edited_ranges_for_transaction::<Point>(transaction)
 6317                    .collect::<Vec<_>>();
 6318                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6319                    PathKey::for_buffer(buffer_handle, cx),
 6320                    buffer_handle.clone(),
 6321                    edited_ranges,
 6322                    multibuffer_context_lines(cx),
 6323                    cx,
 6324                );
 6325
 6326                ranges_to_highlight.extend(ranges);
 6327            }
 6328            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6329            multibuffer
 6330        })?;
 6331
 6332        workspace.update_in(cx, |workspace, window, cx| {
 6333            let project = workspace.project().clone();
 6334            let editor =
 6335                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6336            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6337            editor.update(cx, |editor, cx| {
 6338                editor.highlight_background::<Self>(
 6339                    &ranges_to_highlight,
 6340                    |theme| theme.colors().editor_highlighted_line_background,
 6341                    cx,
 6342                );
 6343            });
 6344        })?;
 6345
 6346        Ok(())
 6347    }
 6348
 6349    pub fn clear_code_action_providers(&mut self) {
 6350        self.code_action_providers.clear();
 6351        self.available_code_actions.take();
 6352    }
 6353
 6354    pub fn add_code_action_provider(
 6355        &mut self,
 6356        provider: Rc<dyn CodeActionProvider>,
 6357        window: &mut Window,
 6358        cx: &mut Context<Self>,
 6359    ) {
 6360        if self
 6361            .code_action_providers
 6362            .iter()
 6363            .any(|existing_provider| existing_provider.id() == provider.id())
 6364        {
 6365            return;
 6366        }
 6367
 6368        self.code_action_providers.push(provider);
 6369        self.refresh_code_actions(window, cx);
 6370    }
 6371
 6372    pub fn remove_code_action_provider(
 6373        &mut self,
 6374        id: Arc<str>,
 6375        window: &mut Window,
 6376        cx: &mut Context<Self>,
 6377    ) {
 6378        self.code_action_providers
 6379            .retain(|provider| provider.id() != id);
 6380        self.refresh_code_actions(window, cx);
 6381    }
 6382
 6383    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6384        !self.code_action_providers.is_empty()
 6385            && EditorSettings::get_global(cx).toolbar.code_actions
 6386    }
 6387
 6388    pub fn has_available_code_actions(&self) -> bool {
 6389        self.available_code_actions
 6390            .as_ref()
 6391            .is_some_and(|(_, actions)| !actions.is_empty())
 6392    }
 6393
 6394    fn render_inline_code_actions(
 6395        &self,
 6396        icon_size: ui::IconSize,
 6397        display_row: DisplayRow,
 6398        is_active: bool,
 6399        cx: &mut Context<Self>,
 6400    ) -> AnyElement {
 6401        let show_tooltip = !self.context_menu_visible();
 6402        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6403            .icon_size(icon_size)
 6404            .shape(ui::IconButtonShape::Square)
 6405            .icon_color(ui::Color::Hidden)
 6406            .toggle_state(is_active)
 6407            .when(show_tooltip, |this| {
 6408                this.tooltip({
 6409                    let focus_handle = self.focus_handle.clone();
 6410                    move |_window, cx| {
 6411                        Tooltip::for_action_in(
 6412                            "Toggle Code Actions",
 6413                            &ToggleCodeActions {
 6414                                deployed_from: None,
 6415                                quick_launch: false,
 6416                            },
 6417                            &focus_handle,
 6418                            cx,
 6419                        )
 6420                    }
 6421                })
 6422            })
 6423            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6424                window.focus(&editor.focus_handle(cx));
 6425                editor.toggle_code_actions(
 6426                    &crate::actions::ToggleCodeActions {
 6427                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6428                            display_row,
 6429                        )),
 6430                        quick_launch: false,
 6431                    },
 6432                    window,
 6433                    cx,
 6434                );
 6435            }))
 6436            .into_any_element()
 6437    }
 6438
 6439    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6440        &self.context_menu
 6441    }
 6442
 6443    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6444        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6445            cx.background_executor()
 6446                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6447                .await;
 6448
 6449            let (start_buffer, start, _, end, newest_selection) = this
 6450                .update(cx, |this, cx| {
 6451                    let newest_selection = this.selections.newest_anchor().clone();
 6452                    if newest_selection.head().diff_base_anchor.is_some() {
 6453                        return None;
 6454                    }
 6455                    let display_snapshot = this.display_snapshot(cx);
 6456                    let newest_selection_adjusted =
 6457                        this.selections.newest_adjusted(&display_snapshot);
 6458                    let buffer = this.buffer.read(cx);
 6459
 6460                    let (start_buffer, start) =
 6461                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6462                    let (end_buffer, end) =
 6463                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6464
 6465                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6466                })?
 6467                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6468                .context(
 6469                    "Expected selection to lie in a single buffer when refreshing code actions",
 6470                )?;
 6471            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6472                let providers = this.code_action_providers.clone();
 6473                let tasks = this
 6474                    .code_action_providers
 6475                    .iter()
 6476                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6477                    .collect::<Vec<_>>();
 6478                (providers, tasks)
 6479            })?;
 6480
 6481            let mut actions = Vec::new();
 6482            for (provider, provider_actions) in
 6483                providers.into_iter().zip(future::join_all(tasks).await)
 6484            {
 6485                if let Some(provider_actions) = provider_actions.log_err() {
 6486                    actions.extend(provider_actions.into_iter().map(|action| {
 6487                        AvailableCodeAction {
 6488                            excerpt_id: newest_selection.start.excerpt_id,
 6489                            action,
 6490                            provider: provider.clone(),
 6491                        }
 6492                    }));
 6493                }
 6494            }
 6495
 6496            this.update(cx, |this, cx| {
 6497                this.available_code_actions = if actions.is_empty() {
 6498                    None
 6499                } else {
 6500                    Some((
 6501                        Location {
 6502                            buffer: start_buffer,
 6503                            range: start..end,
 6504                        },
 6505                        actions.into(),
 6506                    ))
 6507                };
 6508                cx.notify();
 6509            })
 6510        }));
 6511    }
 6512
 6513    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6514        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6515            self.show_git_blame_inline = false;
 6516
 6517            self.show_git_blame_inline_delay_task =
 6518                Some(cx.spawn_in(window, async move |this, cx| {
 6519                    cx.background_executor().timer(delay).await;
 6520
 6521                    this.update(cx, |this, cx| {
 6522                        this.show_git_blame_inline = true;
 6523                        cx.notify();
 6524                    })
 6525                    .log_err();
 6526                }));
 6527        }
 6528    }
 6529
 6530    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6531        let snapshot = self.snapshot(window, cx);
 6532        let cursor = self
 6533            .selections
 6534            .newest::<Point>(&snapshot.display_snapshot)
 6535            .head();
 6536        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6537        else {
 6538            return;
 6539        };
 6540
 6541        let Some(blame) = self.blame.as_ref() else {
 6542            return;
 6543        };
 6544
 6545        let row_info = RowInfo {
 6546            buffer_id: Some(buffer.remote_id()),
 6547            buffer_row: Some(point.row),
 6548            ..Default::default()
 6549        };
 6550        let Some((buffer, blame_entry)) = blame
 6551            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6552            .flatten()
 6553        else {
 6554            return;
 6555        };
 6556
 6557        let anchor = self.selections.newest_anchor().head();
 6558        let position = self.to_pixel_point(anchor, &snapshot, window);
 6559        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6560            self.show_blame_popover(
 6561                buffer,
 6562                &blame_entry,
 6563                position + last_bounds.origin,
 6564                true,
 6565                cx,
 6566            );
 6567        };
 6568    }
 6569
 6570    fn show_blame_popover(
 6571        &mut self,
 6572        buffer: BufferId,
 6573        blame_entry: &BlameEntry,
 6574        position: gpui::Point<Pixels>,
 6575        ignore_timeout: bool,
 6576        cx: &mut Context<Self>,
 6577    ) {
 6578        if let Some(state) = &mut self.inline_blame_popover {
 6579            state.hide_task.take();
 6580        } else {
 6581            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6582            let blame_entry = blame_entry.clone();
 6583            let show_task = cx.spawn(async move |editor, cx| {
 6584                if !ignore_timeout {
 6585                    cx.background_executor()
 6586                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6587                        .await;
 6588                }
 6589                editor
 6590                    .update(cx, |editor, cx| {
 6591                        editor.inline_blame_popover_show_task.take();
 6592                        let Some(blame) = editor.blame.as_ref() else {
 6593                            return;
 6594                        };
 6595                        let blame = blame.read(cx);
 6596                        let details = blame.details_for_entry(buffer, &blame_entry);
 6597                        let markdown = cx.new(|cx| {
 6598                            Markdown::new(
 6599                                details
 6600                                    .as_ref()
 6601                                    .map(|message| message.message.clone())
 6602                                    .unwrap_or_default(),
 6603                                None,
 6604                                None,
 6605                                cx,
 6606                            )
 6607                        });
 6608                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6609                            position,
 6610                            hide_task: None,
 6611                            popover_bounds: None,
 6612                            popover_state: InlineBlamePopoverState {
 6613                                scroll_handle: ScrollHandle::new(),
 6614                                commit_message: details,
 6615                                markdown,
 6616                            },
 6617                            keyboard_grace: ignore_timeout,
 6618                        });
 6619                        cx.notify();
 6620                    })
 6621                    .ok();
 6622            });
 6623            self.inline_blame_popover_show_task = Some(show_task);
 6624        }
 6625    }
 6626
 6627    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6628        self.inline_blame_popover_show_task.take();
 6629        if let Some(state) = &mut self.inline_blame_popover {
 6630            let hide_task = cx.spawn(async move |editor, cx| {
 6631                if !ignore_timeout {
 6632                    cx.background_executor()
 6633                        .timer(std::time::Duration::from_millis(100))
 6634                        .await;
 6635                }
 6636                editor
 6637                    .update(cx, |editor, cx| {
 6638                        editor.inline_blame_popover.take();
 6639                        cx.notify();
 6640                    })
 6641                    .ok();
 6642            });
 6643            state.hide_task = Some(hide_task);
 6644            true
 6645        } else {
 6646            false
 6647        }
 6648    }
 6649
 6650    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6651        if self.pending_rename.is_some() {
 6652            return None;
 6653        }
 6654
 6655        let provider = self.semantics_provider.clone()?;
 6656        let buffer = self.buffer.read(cx);
 6657        let newest_selection = self.selections.newest_anchor().clone();
 6658        let cursor_position = newest_selection.head();
 6659        let (cursor_buffer, cursor_buffer_position) =
 6660            buffer.text_anchor_for_position(cursor_position, cx)?;
 6661        let (tail_buffer, tail_buffer_position) =
 6662            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6663        if cursor_buffer != tail_buffer {
 6664            return None;
 6665        }
 6666
 6667        let snapshot = cursor_buffer.read(cx).snapshot();
 6668        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6669        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6670        if start_word_range != end_word_range {
 6671            self.document_highlights_task.take();
 6672            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6673            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6674            return None;
 6675        }
 6676
 6677        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6678        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6679            cx.background_executor()
 6680                .timer(Duration::from_millis(debounce))
 6681                .await;
 6682
 6683            let highlights = if let Some(highlights) = cx
 6684                .update(|cx| {
 6685                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6686                })
 6687                .ok()
 6688                .flatten()
 6689            {
 6690                highlights.await.log_err()
 6691            } else {
 6692                None
 6693            };
 6694
 6695            if let Some(highlights) = highlights {
 6696                this.update(cx, |this, cx| {
 6697                    if this.pending_rename.is_some() {
 6698                        return;
 6699                    }
 6700
 6701                    let buffer = this.buffer.read(cx);
 6702                    if buffer
 6703                        .text_anchor_for_position(cursor_position, cx)
 6704                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6705                    {
 6706                        return;
 6707                    }
 6708
 6709                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6710                    let mut write_ranges = Vec::new();
 6711                    let mut read_ranges = Vec::new();
 6712                    for highlight in highlights {
 6713                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6714                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6715                        {
 6716                            let start = highlight
 6717                                .range
 6718                                .start
 6719                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6720                            let end = highlight
 6721                                .range
 6722                                .end
 6723                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6724                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6725                                continue;
 6726                            }
 6727
 6728                            let range =
 6729                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6730                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6731                                write_ranges.push(range);
 6732                            } else {
 6733                                read_ranges.push(range);
 6734                            }
 6735                        }
 6736                    }
 6737
 6738                    this.highlight_background::<DocumentHighlightRead>(
 6739                        &read_ranges,
 6740                        |theme| theme.colors().editor_document_highlight_read_background,
 6741                        cx,
 6742                    );
 6743                    this.highlight_background::<DocumentHighlightWrite>(
 6744                        &write_ranges,
 6745                        |theme| theme.colors().editor_document_highlight_write_background,
 6746                        cx,
 6747                    );
 6748                    cx.notify();
 6749                })
 6750                .log_err();
 6751            }
 6752        }));
 6753        None
 6754    }
 6755
 6756    fn prepare_highlight_query_from_selection(
 6757        &mut self,
 6758        window: &Window,
 6759        cx: &mut Context<Editor>,
 6760    ) -> Option<(String, Range<Anchor>)> {
 6761        if matches!(self.mode, EditorMode::SingleLine) {
 6762            return None;
 6763        }
 6764        if !EditorSettings::get_global(cx).selection_highlight {
 6765            return None;
 6766        }
 6767        if self.selections.count() != 1 || self.selections.line_mode() {
 6768            return None;
 6769        }
 6770        let snapshot = self.snapshot(window, cx);
 6771        let selection = self.selections.newest::<Point>(&snapshot);
 6772        // If the selection spans multiple rows OR it is empty
 6773        if selection.start.row != selection.end.row
 6774            || selection.start.column == selection.end.column
 6775        {
 6776            return None;
 6777        }
 6778        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6779        let query = snapshot
 6780            .buffer_snapshot()
 6781            .text_for_range(selection_anchor_range.clone())
 6782            .collect::<String>();
 6783        if query.trim().is_empty() {
 6784            return None;
 6785        }
 6786        Some((query, selection_anchor_range))
 6787    }
 6788
 6789    fn update_selection_occurrence_highlights(
 6790        &mut self,
 6791        query_text: String,
 6792        query_range: Range<Anchor>,
 6793        multi_buffer_range_to_query: Range<Point>,
 6794        use_debounce: bool,
 6795        window: &mut Window,
 6796        cx: &mut Context<Editor>,
 6797    ) -> Task<()> {
 6798        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6799        cx.spawn_in(window, async move |editor, cx| {
 6800            if use_debounce {
 6801                cx.background_executor()
 6802                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6803                    .await;
 6804            }
 6805            let match_task = cx.background_spawn(async move {
 6806                let buffer_ranges = multi_buffer_snapshot
 6807                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6808                    .into_iter()
 6809                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6810                let mut match_ranges = Vec::new();
 6811                let Ok(regex) = project::search::SearchQuery::text(
 6812                    query_text.clone(),
 6813                    false,
 6814                    false,
 6815                    false,
 6816                    Default::default(),
 6817                    Default::default(),
 6818                    false,
 6819                    None,
 6820                ) else {
 6821                    return Vec::default();
 6822                };
 6823                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6824                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6825                    match_ranges.extend(
 6826                        regex
 6827                            .search(buffer_snapshot, Some(search_range.clone()))
 6828                            .await
 6829                            .into_iter()
 6830                            .filter_map(|match_range| {
 6831                                let match_start = buffer_snapshot
 6832                                    .anchor_after(search_range.start + match_range.start);
 6833                                let match_end = buffer_snapshot
 6834                                    .anchor_before(search_range.start + match_range.end);
 6835                                let match_anchor_range = Anchor::range_in_buffer(
 6836                                    excerpt_id,
 6837                                    buffer_snapshot.remote_id(),
 6838                                    match_start..match_end,
 6839                                );
 6840                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6841                            }),
 6842                    );
 6843                }
 6844                match_ranges
 6845            });
 6846            let match_ranges = match_task.await;
 6847            editor
 6848                .update_in(cx, |editor, _, cx| {
 6849                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6850                    if !match_ranges.is_empty() {
 6851                        editor.highlight_background::<SelectedTextHighlight>(
 6852                            &match_ranges,
 6853                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6854                            cx,
 6855                        )
 6856                    }
 6857                })
 6858                .log_err();
 6859        })
 6860    }
 6861
 6862    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6863        struct NewlineFold;
 6864        let type_id = std::any::TypeId::of::<NewlineFold>();
 6865        if !self.mode.is_single_line() {
 6866            return;
 6867        }
 6868        let snapshot = self.snapshot(window, cx);
 6869        if snapshot.buffer_snapshot().max_point().row == 0 {
 6870            return;
 6871        }
 6872        let task = cx.background_spawn(async move {
 6873            let new_newlines = snapshot
 6874                .buffer_chars_at(0)
 6875                .filter_map(|(c, i)| {
 6876                    if c == '\n' {
 6877                        Some(
 6878                            snapshot.buffer_snapshot().anchor_after(i)
 6879                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 6880                        )
 6881                    } else {
 6882                        None
 6883                    }
 6884                })
 6885                .collect::<Vec<_>>();
 6886            let existing_newlines = snapshot
 6887                .folds_in_range(0..snapshot.buffer_snapshot().len())
 6888                .filter_map(|fold| {
 6889                    if fold.placeholder.type_tag == Some(type_id) {
 6890                        Some(fold.range.start..fold.range.end)
 6891                    } else {
 6892                        None
 6893                    }
 6894                })
 6895                .collect::<Vec<_>>();
 6896
 6897            (new_newlines, existing_newlines)
 6898        });
 6899        self.folding_newlines = cx.spawn(async move |this, cx| {
 6900            let (new_newlines, existing_newlines) = task.await;
 6901            if new_newlines == existing_newlines {
 6902                return;
 6903            }
 6904            let placeholder = FoldPlaceholder {
 6905                render: Arc::new(move |_, _, cx| {
 6906                    div()
 6907                        .bg(cx.theme().status().hint_background)
 6908                        .border_b_1()
 6909                        .size_full()
 6910                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6911                        .border_color(cx.theme().status().hint)
 6912                        .child("\\n")
 6913                        .into_any()
 6914                }),
 6915                constrain_width: false,
 6916                merge_adjacent: false,
 6917                type_tag: Some(type_id),
 6918            };
 6919            let creases = new_newlines
 6920                .into_iter()
 6921                .map(|range| Crease::simple(range, placeholder.clone()))
 6922                .collect();
 6923            this.update(cx, |this, cx| {
 6924                this.display_map.update(cx, |display_map, cx| {
 6925                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6926                    display_map.fold(creases, cx);
 6927                });
 6928            })
 6929            .ok();
 6930        });
 6931    }
 6932
 6933    fn refresh_selected_text_highlights(
 6934        &mut self,
 6935        on_buffer_edit: bool,
 6936        window: &mut Window,
 6937        cx: &mut Context<Editor>,
 6938    ) {
 6939        let Some((query_text, query_range)) =
 6940            self.prepare_highlight_query_from_selection(window, cx)
 6941        else {
 6942            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6943            self.quick_selection_highlight_task.take();
 6944            self.debounced_selection_highlight_task.take();
 6945            return;
 6946        };
 6947        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6948        if on_buffer_edit
 6949            || self
 6950                .quick_selection_highlight_task
 6951                .as_ref()
 6952                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6953        {
 6954            let multi_buffer_visible_start = self
 6955                .scroll_manager
 6956                .anchor()
 6957                .anchor
 6958                .to_point(&multi_buffer_snapshot);
 6959            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6960                multi_buffer_visible_start
 6961                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6962                Bias::Left,
 6963            );
 6964            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6965            self.quick_selection_highlight_task = Some((
 6966                query_range.clone(),
 6967                self.update_selection_occurrence_highlights(
 6968                    query_text.clone(),
 6969                    query_range.clone(),
 6970                    multi_buffer_visible_range,
 6971                    false,
 6972                    window,
 6973                    cx,
 6974                ),
 6975            ));
 6976        }
 6977        if on_buffer_edit
 6978            || self
 6979                .debounced_selection_highlight_task
 6980                .as_ref()
 6981                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6982        {
 6983            let multi_buffer_start = multi_buffer_snapshot
 6984                .anchor_before(0)
 6985                .to_point(&multi_buffer_snapshot);
 6986            let multi_buffer_end = multi_buffer_snapshot
 6987                .anchor_after(multi_buffer_snapshot.len())
 6988                .to_point(&multi_buffer_snapshot);
 6989            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6990            self.debounced_selection_highlight_task = Some((
 6991                query_range.clone(),
 6992                self.update_selection_occurrence_highlights(
 6993                    query_text,
 6994                    query_range,
 6995                    multi_buffer_full_range,
 6996                    true,
 6997                    window,
 6998                    cx,
 6999                ),
 7000            ));
 7001        }
 7002    }
 7003
 7004    pub fn refresh_edit_prediction(
 7005        &mut self,
 7006        debounce: bool,
 7007        user_requested: bool,
 7008        window: &mut Window,
 7009        cx: &mut Context<Self>,
 7010    ) -> Option<()> {
 7011        if DisableAiSettings::get_global(cx).disable_ai {
 7012            return None;
 7013        }
 7014
 7015        let provider = self.edit_prediction_provider()?;
 7016        let cursor = self.selections.newest_anchor().head();
 7017        let (buffer, cursor_buffer_position) =
 7018            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7019
 7020        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7021            self.discard_edit_prediction(false, cx);
 7022            return None;
 7023        }
 7024
 7025        self.update_visible_edit_prediction(window, cx);
 7026
 7027        if !user_requested
 7028            && (!self.should_show_edit_predictions()
 7029                || !self.is_focused(window)
 7030                || buffer.read(cx).is_empty())
 7031        {
 7032            self.discard_edit_prediction(false, cx);
 7033            return None;
 7034        }
 7035
 7036        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7037        Some(())
 7038    }
 7039
 7040    fn show_edit_predictions_in_menu(&self) -> bool {
 7041        match self.edit_prediction_settings {
 7042            EditPredictionSettings::Disabled => false,
 7043            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7044        }
 7045    }
 7046
 7047    pub fn edit_predictions_enabled(&self) -> bool {
 7048        match self.edit_prediction_settings {
 7049            EditPredictionSettings::Disabled => false,
 7050            EditPredictionSettings::Enabled { .. } => true,
 7051        }
 7052    }
 7053
 7054    fn edit_prediction_requires_modifier(&self) -> bool {
 7055        match self.edit_prediction_settings {
 7056            EditPredictionSettings::Disabled => false,
 7057            EditPredictionSettings::Enabled {
 7058                preview_requires_modifier,
 7059                ..
 7060            } => preview_requires_modifier,
 7061        }
 7062    }
 7063
 7064    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7065        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7066            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7067            self.discard_edit_prediction(false, cx);
 7068        } else {
 7069            let selection = self.selections.newest_anchor();
 7070            let cursor = selection.head();
 7071
 7072            if let Some((buffer, cursor_buffer_position)) =
 7073                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7074            {
 7075                self.edit_prediction_settings =
 7076                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7077            }
 7078        }
 7079    }
 7080
 7081    fn edit_prediction_settings_at_position(
 7082        &self,
 7083        buffer: &Entity<Buffer>,
 7084        buffer_position: language::Anchor,
 7085        cx: &App,
 7086    ) -> EditPredictionSettings {
 7087        if !self.mode.is_full()
 7088            || !self.show_edit_predictions_override.unwrap_or(true)
 7089            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7090        {
 7091            return EditPredictionSettings::Disabled;
 7092        }
 7093
 7094        let buffer = buffer.read(cx);
 7095
 7096        let file = buffer.file();
 7097
 7098        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7099            return EditPredictionSettings::Disabled;
 7100        };
 7101
 7102        let by_provider = matches!(
 7103            self.menu_edit_predictions_policy,
 7104            MenuEditPredictionsPolicy::ByProvider
 7105        );
 7106
 7107        let show_in_menu = by_provider
 7108            && self
 7109                .edit_prediction_provider
 7110                .as_ref()
 7111                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7112
 7113        let preview_requires_modifier =
 7114            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7115
 7116        EditPredictionSettings::Enabled {
 7117            show_in_menu,
 7118            preview_requires_modifier,
 7119        }
 7120    }
 7121
 7122    fn should_show_edit_predictions(&self) -> bool {
 7123        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7124    }
 7125
 7126    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7127        matches!(
 7128            self.edit_prediction_preview,
 7129            EditPredictionPreview::Active { .. }
 7130        )
 7131    }
 7132
 7133    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7134        let cursor = self.selections.newest_anchor().head();
 7135        if let Some((buffer, cursor_position)) =
 7136            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7137        {
 7138            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7139        } else {
 7140            false
 7141        }
 7142    }
 7143
 7144    pub fn supports_minimap(&self, cx: &App) -> bool {
 7145        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7146    }
 7147
 7148    fn edit_predictions_enabled_in_buffer(
 7149        &self,
 7150        buffer: &Entity<Buffer>,
 7151        buffer_position: language::Anchor,
 7152        cx: &App,
 7153    ) -> bool {
 7154        maybe!({
 7155            if self.read_only(cx) {
 7156                return Some(false);
 7157            }
 7158            let provider = self.edit_prediction_provider()?;
 7159            if !provider.is_enabled(buffer, buffer_position, cx) {
 7160                return Some(false);
 7161            }
 7162            let buffer = buffer.read(cx);
 7163            let Some(file) = buffer.file() else {
 7164                return Some(true);
 7165            };
 7166            let settings = all_language_settings(Some(file), cx);
 7167            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7168        })
 7169        .unwrap_or(false)
 7170    }
 7171
 7172    fn cycle_edit_prediction(
 7173        &mut self,
 7174        direction: Direction,
 7175        window: &mut Window,
 7176        cx: &mut Context<Self>,
 7177    ) -> Option<()> {
 7178        let provider = self.edit_prediction_provider()?;
 7179        let cursor = self.selections.newest_anchor().head();
 7180        let (buffer, cursor_buffer_position) =
 7181            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7182        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7183            return None;
 7184        }
 7185
 7186        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7187        self.update_visible_edit_prediction(window, cx);
 7188
 7189        Some(())
 7190    }
 7191
 7192    pub fn show_edit_prediction(
 7193        &mut self,
 7194        _: &ShowEditPrediction,
 7195        window: &mut Window,
 7196        cx: &mut Context<Self>,
 7197    ) {
 7198        if !self.has_active_edit_prediction() {
 7199            self.refresh_edit_prediction(false, true, window, cx);
 7200            return;
 7201        }
 7202
 7203        self.update_visible_edit_prediction(window, cx);
 7204    }
 7205
 7206    pub fn display_cursor_names(
 7207        &mut self,
 7208        _: &DisplayCursorNames,
 7209        window: &mut Window,
 7210        cx: &mut Context<Self>,
 7211    ) {
 7212        self.show_cursor_names(window, cx);
 7213    }
 7214
 7215    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7216        self.show_cursor_names = true;
 7217        cx.notify();
 7218        cx.spawn_in(window, async move |this, cx| {
 7219            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7220            this.update(cx, |this, cx| {
 7221                this.show_cursor_names = false;
 7222                cx.notify()
 7223            })
 7224            .ok()
 7225        })
 7226        .detach();
 7227    }
 7228
 7229    pub fn next_edit_prediction(
 7230        &mut self,
 7231        _: &NextEditPrediction,
 7232        window: &mut Window,
 7233        cx: &mut Context<Self>,
 7234    ) {
 7235        if self.has_active_edit_prediction() {
 7236            self.cycle_edit_prediction(Direction::Next, window, cx);
 7237        } else {
 7238            let is_copilot_disabled = self
 7239                .refresh_edit_prediction(false, true, window, cx)
 7240                .is_none();
 7241            if is_copilot_disabled {
 7242                cx.propagate();
 7243            }
 7244        }
 7245    }
 7246
 7247    pub fn previous_edit_prediction(
 7248        &mut self,
 7249        _: &PreviousEditPrediction,
 7250        window: &mut Window,
 7251        cx: &mut Context<Self>,
 7252    ) {
 7253        if self.has_active_edit_prediction() {
 7254            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7255        } else {
 7256            let is_copilot_disabled = self
 7257                .refresh_edit_prediction(false, true, window, cx)
 7258                .is_none();
 7259            if is_copilot_disabled {
 7260                cx.propagate();
 7261            }
 7262        }
 7263    }
 7264
 7265    pub fn accept_edit_prediction(
 7266        &mut self,
 7267        _: &AcceptEditPrediction,
 7268        window: &mut Window,
 7269        cx: &mut Context<Self>,
 7270    ) {
 7271        if self.show_edit_predictions_in_menu() {
 7272            self.hide_context_menu(window, cx);
 7273        }
 7274
 7275        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7276            return;
 7277        };
 7278
 7279        match &active_edit_prediction.completion {
 7280            EditPrediction::MoveWithin { target, .. } => {
 7281                let target = *target;
 7282
 7283                if let Some(position_map) = &self.last_position_map {
 7284                    if position_map
 7285                        .visible_row_range
 7286                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7287                        || !self.edit_prediction_requires_modifier()
 7288                    {
 7289                        self.unfold_ranges(&[target..target], true, false, cx);
 7290                        // Note that this is also done in vim's handler of the Tab action.
 7291                        self.change_selections(
 7292                            SelectionEffects::scroll(Autoscroll::newest()),
 7293                            window,
 7294                            cx,
 7295                            |selections| {
 7296                                selections.select_anchor_ranges([target..target]);
 7297                            },
 7298                        );
 7299                        self.clear_row_highlights::<EditPredictionPreview>();
 7300
 7301                        self.edit_prediction_preview
 7302                            .set_previous_scroll_position(None);
 7303                    } else {
 7304                        self.edit_prediction_preview
 7305                            .set_previous_scroll_position(Some(
 7306                                position_map.snapshot.scroll_anchor,
 7307                            ));
 7308
 7309                        self.highlight_rows::<EditPredictionPreview>(
 7310                            target..target,
 7311                            cx.theme().colors().editor_highlighted_line_background,
 7312                            RowHighlightOptions {
 7313                                autoscroll: true,
 7314                                ..Default::default()
 7315                            },
 7316                            cx,
 7317                        );
 7318                        self.request_autoscroll(Autoscroll::fit(), cx);
 7319                    }
 7320                }
 7321            }
 7322            EditPrediction::MoveOutside { snapshot, target } => {
 7323                if let Some(workspace) = self.workspace() {
 7324                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7325                        .detach_and_log_err(cx);
 7326                }
 7327            }
 7328            EditPrediction::Edit { edits, .. } => {
 7329                self.report_edit_prediction_event(
 7330                    active_edit_prediction.completion_id.clone(),
 7331                    true,
 7332                    cx,
 7333                );
 7334
 7335                if let Some(provider) = self.edit_prediction_provider() {
 7336                    provider.accept(cx);
 7337                }
 7338
 7339                // Store the transaction ID and selections before applying the edit
 7340                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7341
 7342                let snapshot = self.buffer.read(cx).snapshot(cx);
 7343                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7344
 7345                self.buffer.update(cx, |buffer, cx| {
 7346                    buffer.edit(edits.iter().cloned(), None, cx)
 7347                });
 7348
 7349                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7350                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7351                });
 7352
 7353                let selections = self.selections.disjoint_anchors_arc();
 7354                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7355                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7356                    if has_new_transaction {
 7357                        self.selection_history
 7358                            .insert_transaction(transaction_id_now, selections);
 7359                    }
 7360                }
 7361
 7362                self.update_visible_edit_prediction(window, cx);
 7363                if self.active_edit_prediction.is_none() {
 7364                    self.refresh_edit_prediction(true, true, window, cx);
 7365                }
 7366
 7367                cx.notify();
 7368            }
 7369        }
 7370
 7371        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7372    }
 7373
 7374    pub fn accept_partial_edit_prediction(
 7375        &mut self,
 7376        _: &AcceptPartialEditPrediction,
 7377        window: &mut Window,
 7378        cx: &mut Context<Self>,
 7379    ) {
 7380        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7381            return;
 7382        };
 7383        if self.selections.count() != 1 {
 7384            return;
 7385        }
 7386
 7387        match &active_edit_prediction.completion {
 7388            EditPrediction::MoveWithin { target, .. } => {
 7389                let target = *target;
 7390                self.change_selections(
 7391                    SelectionEffects::scroll(Autoscroll::newest()),
 7392                    window,
 7393                    cx,
 7394                    |selections| {
 7395                        selections.select_anchor_ranges([target..target]);
 7396                    },
 7397                );
 7398            }
 7399            EditPrediction::MoveOutside { snapshot, target } => {
 7400                if let Some(workspace) = self.workspace() {
 7401                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7402                        .detach_and_log_err(cx);
 7403                }
 7404            }
 7405            EditPrediction::Edit { edits, .. } => {
 7406                self.report_edit_prediction_event(
 7407                    active_edit_prediction.completion_id.clone(),
 7408                    true,
 7409                    cx,
 7410                );
 7411
 7412                // Find an insertion that starts at the cursor position.
 7413                let snapshot = self.buffer.read(cx).snapshot(cx);
 7414                let cursor_offset = self
 7415                    .selections
 7416                    .newest::<usize>(&self.display_snapshot(cx))
 7417                    .head();
 7418                let insertion = edits.iter().find_map(|(range, text)| {
 7419                    let range = range.to_offset(&snapshot);
 7420                    if range.is_empty() && range.start == cursor_offset {
 7421                        Some(text)
 7422                    } else {
 7423                        None
 7424                    }
 7425                });
 7426
 7427                if let Some(text) = insertion {
 7428                    let mut partial_completion = text
 7429                        .chars()
 7430                        .by_ref()
 7431                        .take_while(|c| c.is_alphabetic())
 7432                        .collect::<String>();
 7433                    if partial_completion.is_empty() {
 7434                        partial_completion = text
 7435                            .chars()
 7436                            .by_ref()
 7437                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7438                            .collect::<String>();
 7439                    }
 7440
 7441                    cx.emit(EditorEvent::InputHandled {
 7442                        utf16_range_to_replace: None,
 7443                        text: partial_completion.clone().into(),
 7444                    });
 7445
 7446                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7447
 7448                    self.refresh_edit_prediction(true, true, window, cx);
 7449                    cx.notify();
 7450                } else {
 7451                    self.accept_edit_prediction(&Default::default(), window, cx);
 7452                }
 7453            }
 7454        }
 7455    }
 7456
 7457    fn discard_edit_prediction(
 7458        &mut self,
 7459        should_report_edit_prediction_event: bool,
 7460        cx: &mut Context<Self>,
 7461    ) -> bool {
 7462        if should_report_edit_prediction_event {
 7463            let completion_id = self
 7464                .active_edit_prediction
 7465                .as_ref()
 7466                .and_then(|active_completion| active_completion.completion_id.clone());
 7467
 7468            self.report_edit_prediction_event(completion_id, false, cx);
 7469        }
 7470
 7471        if let Some(provider) = self.edit_prediction_provider() {
 7472            provider.discard(cx);
 7473        }
 7474
 7475        self.take_active_edit_prediction(cx)
 7476    }
 7477
 7478    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7479        let Some(provider) = self.edit_prediction_provider() else {
 7480            return;
 7481        };
 7482
 7483        let Some((_, buffer, _)) = self
 7484            .buffer
 7485            .read(cx)
 7486            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7487        else {
 7488            return;
 7489        };
 7490
 7491        let extension = buffer
 7492            .read(cx)
 7493            .file()
 7494            .and_then(|file| Some(file.path().extension()?.to_string()));
 7495
 7496        let event_type = match accepted {
 7497            true => "Edit Prediction Accepted",
 7498            false => "Edit Prediction Discarded",
 7499        };
 7500        telemetry::event!(
 7501            event_type,
 7502            provider = provider.name(),
 7503            prediction_id = id,
 7504            suggestion_accepted = accepted,
 7505            file_extension = extension,
 7506        );
 7507    }
 7508
 7509    fn open_editor_at_anchor(
 7510        snapshot: &language::BufferSnapshot,
 7511        target: language::Anchor,
 7512        workspace: &Entity<Workspace>,
 7513        window: &mut Window,
 7514        cx: &mut App,
 7515    ) -> Task<Result<()>> {
 7516        workspace.update(cx, |workspace, cx| {
 7517            let path = snapshot.file().map(|file| file.full_path(cx));
 7518            let Some(path) =
 7519                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7520            else {
 7521                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7522            };
 7523            let target = text::ToPoint::to_point(&target, snapshot);
 7524            let item = workspace.open_path(path, None, true, window, cx);
 7525            window.spawn(cx, async move |cx| {
 7526                let Some(editor) = item.await?.downcast::<Editor>() else {
 7527                    return Ok(());
 7528                };
 7529                editor
 7530                    .update_in(cx, |editor, window, cx| {
 7531                        editor.go_to_singleton_buffer_point(target, window, cx);
 7532                    })
 7533                    .ok();
 7534                anyhow::Ok(())
 7535            })
 7536        })
 7537    }
 7538
 7539    pub fn has_active_edit_prediction(&self) -> bool {
 7540        self.active_edit_prediction.is_some()
 7541    }
 7542
 7543    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7544        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7545            return false;
 7546        };
 7547
 7548        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7549        self.clear_highlights::<EditPredictionHighlight>(cx);
 7550        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7551        true
 7552    }
 7553
 7554    /// Returns true when we're displaying the edit prediction popover below the cursor
 7555    /// like we are not previewing and the LSP autocomplete menu is visible
 7556    /// or we are in `when_holding_modifier` mode.
 7557    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7558        if self.edit_prediction_preview_is_active()
 7559            || !self.show_edit_predictions_in_menu()
 7560            || !self.edit_predictions_enabled()
 7561        {
 7562            return false;
 7563        }
 7564
 7565        if self.has_visible_completions_menu() {
 7566            return true;
 7567        }
 7568
 7569        has_completion && self.edit_prediction_requires_modifier()
 7570    }
 7571
 7572    fn handle_modifiers_changed(
 7573        &mut self,
 7574        modifiers: Modifiers,
 7575        position_map: &PositionMap,
 7576        window: &mut Window,
 7577        cx: &mut Context<Self>,
 7578    ) {
 7579        // Ensure that the edit prediction preview is updated, even when not
 7580        // enabled, if there's an active edit prediction preview.
 7581        if self.show_edit_predictions_in_menu()
 7582            || matches!(
 7583                self.edit_prediction_preview,
 7584                EditPredictionPreview::Active { .. }
 7585            )
 7586        {
 7587            self.update_edit_prediction_preview(&modifiers, window, cx);
 7588        }
 7589
 7590        self.update_selection_mode(&modifiers, position_map, window, cx);
 7591
 7592        let mouse_position = window.mouse_position();
 7593        if !position_map.text_hitbox.is_hovered(window) {
 7594            return;
 7595        }
 7596
 7597        self.update_hovered_link(
 7598            position_map.point_for_position(mouse_position),
 7599            &position_map.snapshot,
 7600            modifiers,
 7601            window,
 7602            cx,
 7603        )
 7604    }
 7605
 7606    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7607        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7608        if invert {
 7609            match multi_cursor_setting {
 7610                MultiCursorModifier::Alt => modifiers.alt,
 7611                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7612            }
 7613        } else {
 7614            match multi_cursor_setting {
 7615                MultiCursorModifier::Alt => modifiers.secondary(),
 7616                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7617            }
 7618        }
 7619    }
 7620
 7621    fn columnar_selection_mode(
 7622        modifiers: &Modifiers,
 7623        cx: &mut Context<Self>,
 7624    ) -> Option<ColumnarMode> {
 7625        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7626            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7627                Some(ColumnarMode::FromMouse)
 7628            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7629                Some(ColumnarMode::FromSelection)
 7630            } else {
 7631                None
 7632            }
 7633        } else {
 7634            None
 7635        }
 7636    }
 7637
 7638    fn update_selection_mode(
 7639        &mut self,
 7640        modifiers: &Modifiers,
 7641        position_map: &PositionMap,
 7642        window: &mut Window,
 7643        cx: &mut Context<Self>,
 7644    ) {
 7645        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7646            return;
 7647        };
 7648        if self.selections.pending_anchor().is_none() {
 7649            return;
 7650        }
 7651
 7652        let mouse_position = window.mouse_position();
 7653        let point_for_position = position_map.point_for_position(mouse_position);
 7654        let position = point_for_position.previous_valid;
 7655
 7656        self.select(
 7657            SelectPhase::BeginColumnar {
 7658                position,
 7659                reset: false,
 7660                mode,
 7661                goal_column: point_for_position.exact_unclipped.column(),
 7662            },
 7663            window,
 7664            cx,
 7665        );
 7666    }
 7667
 7668    fn update_edit_prediction_preview(
 7669        &mut self,
 7670        modifiers: &Modifiers,
 7671        window: &mut Window,
 7672        cx: &mut Context<Self>,
 7673    ) {
 7674        let mut modifiers_held = false;
 7675        if let Some(accept_keystroke) = self
 7676            .accept_edit_prediction_keybind(false, window, cx)
 7677            .keystroke()
 7678        {
 7679            modifiers_held = modifiers_held
 7680                || (accept_keystroke.modifiers() == modifiers
 7681                    && accept_keystroke.modifiers().modified());
 7682        };
 7683        if let Some(accept_partial_keystroke) = self
 7684            .accept_edit_prediction_keybind(true, window, cx)
 7685            .keystroke()
 7686        {
 7687            modifiers_held = modifiers_held
 7688                || (accept_partial_keystroke.modifiers() == modifiers
 7689                    && accept_partial_keystroke.modifiers().modified());
 7690        }
 7691
 7692        if modifiers_held {
 7693            if matches!(
 7694                self.edit_prediction_preview,
 7695                EditPredictionPreview::Inactive { .. }
 7696            ) {
 7697                self.edit_prediction_preview = EditPredictionPreview::Active {
 7698                    previous_scroll_position: None,
 7699                    since: Instant::now(),
 7700                };
 7701
 7702                self.update_visible_edit_prediction(window, cx);
 7703                cx.notify();
 7704            }
 7705        } else if let EditPredictionPreview::Active {
 7706            previous_scroll_position,
 7707            since,
 7708        } = self.edit_prediction_preview
 7709        {
 7710            if let (Some(previous_scroll_position), Some(position_map)) =
 7711                (previous_scroll_position, self.last_position_map.as_ref())
 7712            {
 7713                self.set_scroll_position(
 7714                    previous_scroll_position
 7715                        .scroll_position(&position_map.snapshot.display_snapshot),
 7716                    window,
 7717                    cx,
 7718                );
 7719            }
 7720
 7721            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7722                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7723            };
 7724            self.clear_row_highlights::<EditPredictionPreview>();
 7725            self.update_visible_edit_prediction(window, cx);
 7726            cx.notify();
 7727        }
 7728    }
 7729
 7730    fn update_visible_edit_prediction(
 7731        &mut self,
 7732        _window: &mut Window,
 7733        cx: &mut Context<Self>,
 7734    ) -> Option<()> {
 7735        if DisableAiSettings::get_global(cx).disable_ai {
 7736            return None;
 7737        }
 7738
 7739        if self.ime_transaction.is_some() {
 7740            self.discard_edit_prediction(false, cx);
 7741            return None;
 7742        }
 7743
 7744        let selection = self.selections.newest_anchor();
 7745        let cursor = selection.head();
 7746        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7747        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7748        let excerpt_id = cursor.excerpt_id;
 7749
 7750        let show_in_menu = self.show_edit_predictions_in_menu();
 7751        let completions_menu_has_precedence = !show_in_menu
 7752            && (self.context_menu.borrow().is_some()
 7753                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7754
 7755        if completions_menu_has_precedence
 7756            || !offset_selection.is_empty()
 7757            || self
 7758                .active_edit_prediction
 7759                .as_ref()
 7760                .is_some_and(|completion| {
 7761                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7762                        return false;
 7763                    };
 7764                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7765                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7766                    !invalidation_range.contains(&offset_selection.head())
 7767                })
 7768        {
 7769            self.discard_edit_prediction(false, cx);
 7770            return None;
 7771        }
 7772
 7773        self.take_active_edit_prediction(cx);
 7774        let Some(provider) = self.edit_prediction_provider() else {
 7775            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7776            return None;
 7777        };
 7778
 7779        let (buffer, cursor_buffer_position) =
 7780            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7781
 7782        self.edit_prediction_settings =
 7783            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7784
 7785        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7786
 7787        if self.edit_prediction_indent_conflict {
 7788            let cursor_point = cursor.to_point(&multibuffer);
 7789
 7790            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7791
 7792            if let Some((_, indent)) = indents.iter().next()
 7793                && indent.len == cursor_point.column
 7794            {
 7795                self.edit_prediction_indent_conflict = false;
 7796            }
 7797        }
 7798
 7799        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7800
 7801        let (completion_id, edits, edit_preview) = match edit_prediction {
 7802            edit_prediction::EditPrediction::Local {
 7803                id,
 7804                edits,
 7805                edit_preview,
 7806            } => (id, edits, edit_preview),
 7807            edit_prediction::EditPrediction::Jump {
 7808                id,
 7809                snapshot,
 7810                target,
 7811            } => {
 7812                self.stale_edit_prediction_in_menu = None;
 7813                self.active_edit_prediction = Some(EditPredictionState {
 7814                    inlay_ids: vec![],
 7815                    completion: EditPrediction::MoveOutside { snapshot, target },
 7816                    completion_id: id,
 7817                    invalidation_range: None,
 7818                });
 7819                cx.notify();
 7820                return Some(());
 7821            }
 7822        };
 7823
 7824        let edits = edits
 7825            .into_iter()
 7826            .flat_map(|(range, new_text)| {
 7827                Some((
 7828                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7829                    new_text,
 7830                ))
 7831            })
 7832            .collect::<Vec<_>>();
 7833        if edits.is_empty() {
 7834            return None;
 7835        }
 7836
 7837        let first_edit_start = edits.first().unwrap().0.start;
 7838        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7839        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7840
 7841        let last_edit_end = edits.last().unwrap().0.end;
 7842        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7843        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7844
 7845        let cursor_row = cursor.to_point(&multibuffer).row;
 7846
 7847        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7848
 7849        let mut inlay_ids = Vec::new();
 7850        let invalidation_row_range;
 7851        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7852            Some(cursor_row..edit_end_row)
 7853        } else if cursor_row > edit_end_row {
 7854            Some(edit_start_row..cursor_row)
 7855        } else {
 7856            None
 7857        };
 7858        let supports_jump = self
 7859            .edit_prediction_provider
 7860            .as_ref()
 7861            .map(|provider| provider.provider.supports_jump_to_edit())
 7862            .unwrap_or(true);
 7863
 7864        let is_move = supports_jump
 7865            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7866        let completion = if is_move {
 7867            invalidation_row_range =
 7868                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7869            let target = first_edit_start;
 7870            EditPrediction::MoveWithin { target, snapshot }
 7871        } else {
 7872            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7873                && !self.edit_predictions_hidden_for_vim_mode;
 7874
 7875            if show_completions_in_buffer {
 7876                if edits
 7877                    .iter()
 7878                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7879                {
 7880                    let mut inlays = Vec::new();
 7881                    for (range, new_text) in &edits {
 7882                        let inlay = Inlay::edit_prediction(
 7883                            post_inc(&mut self.next_inlay_id),
 7884                            range.start,
 7885                            new_text.as_str(),
 7886                        );
 7887                        inlay_ids.push(inlay.id);
 7888                        inlays.push(inlay);
 7889                    }
 7890
 7891                    self.splice_inlays(&[], inlays, cx);
 7892                } else {
 7893                    let background_color = cx.theme().status().deleted_background;
 7894                    self.highlight_text::<EditPredictionHighlight>(
 7895                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7896                        HighlightStyle {
 7897                            background_color: Some(background_color),
 7898                            ..Default::default()
 7899                        },
 7900                        cx,
 7901                    );
 7902                }
 7903            }
 7904
 7905            invalidation_row_range = edit_start_row..edit_end_row;
 7906
 7907            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7908                if provider.show_tab_accept_marker() {
 7909                    EditDisplayMode::TabAccept
 7910                } else {
 7911                    EditDisplayMode::Inline
 7912                }
 7913            } else {
 7914                EditDisplayMode::DiffPopover
 7915            };
 7916
 7917            EditPrediction::Edit {
 7918                edits,
 7919                edit_preview,
 7920                display_mode,
 7921                snapshot,
 7922            }
 7923        };
 7924
 7925        let invalidation_range = multibuffer
 7926            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7927            ..multibuffer.anchor_after(Point::new(
 7928                invalidation_row_range.end,
 7929                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7930            ));
 7931
 7932        self.stale_edit_prediction_in_menu = None;
 7933        self.active_edit_prediction = Some(EditPredictionState {
 7934            inlay_ids,
 7935            completion,
 7936            completion_id,
 7937            invalidation_range: Some(invalidation_range),
 7938        });
 7939
 7940        cx.notify();
 7941
 7942        Some(())
 7943    }
 7944
 7945    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7946        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7947    }
 7948
 7949    fn clear_tasks(&mut self) {
 7950        self.tasks.clear()
 7951    }
 7952
 7953    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7954        if self.tasks.insert(key, value).is_some() {
 7955            // This case should hopefully be rare, but just in case...
 7956            log::error!(
 7957                "multiple different run targets found on a single line, only the last target will be rendered"
 7958            )
 7959        }
 7960    }
 7961
 7962    /// Get all display points of breakpoints that will be rendered within editor
 7963    ///
 7964    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7965    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7966    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7967    fn active_breakpoints(
 7968        &self,
 7969        range: Range<DisplayRow>,
 7970        window: &mut Window,
 7971        cx: &mut Context<Self>,
 7972    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7973        let mut breakpoint_display_points = HashMap::default();
 7974
 7975        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7976            return breakpoint_display_points;
 7977        };
 7978
 7979        let snapshot = self.snapshot(window, cx);
 7980
 7981        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 7982        let Some(project) = self.project() else {
 7983            return breakpoint_display_points;
 7984        };
 7985
 7986        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7987            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7988
 7989        for (buffer_snapshot, range, excerpt_id) in
 7990            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7991        {
 7992            let Some(buffer) = project
 7993                .read(cx)
 7994                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7995            else {
 7996                continue;
 7997            };
 7998            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7999                &buffer,
 8000                Some(
 8001                    buffer_snapshot.anchor_before(range.start)
 8002                        ..buffer_snapshot.anchor_after(range.end),
 8003                ),
 8004                buffer_snapshot,
 8005                cx,
 8006            );
 8007            for (breakpoint, state) in breakpoints {
 8008                let multi_buffer_anchor =
 8009                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8010                let position = multi_buffer_anchor
 8011                    .to_point(&multi_buffer_snapshot)
 8012                    .to_display_point(&snapshot);
 8013
 8014                breakpoint_display_points.insert(
 8015                    position.row(),
 8016                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8017                );
 8018            }
 8019        }
 8020
 8021        breakpoint_display_points
 8022    }
 8023
 8024    fn breakpoint_context_menu(
 8025        &self,
 8026        anchor: Anchor,
 8027        window: &mut Window,
 8028        cx: &mut Context<Self>,
 8029    ) -> Entity<ui::ContextMenu> {
 8030        let weak_editor = cx.weak_entity();
 8031        let focus_handle = self.focus_handle(cx);
 8032
 8033        let row = self
 8034            .buffer
 8035            .read(cx)
 8036            .snapshot(cx)
 8037            .summary_for_anchor::<Point>(&anchor)
 8038            .row;
 8039
 8040        let breakpoint = self
 8041            .breakpoint_at_row(row, window, cx)
 8042            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8043
 8044        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8045            "Edit Log Breakpoint"
 8046        } else {
 8047            "Set Log Breakpoint"
 8048        };
 8049
 8050        let condition_breakpoint_msg = if breakpoint
 8051            .as_ref()
 8052            .is_some_and(|bp| bp.1.condition.is_some())
 8053        {
 8054            "Edit Condition Breakpoint"
 8055        } else {
 8056            "Set Condition Breakpoint"
 8057        };
 8058
 8059        let hit_condition_breakpoint_msg = if breakpoint
 8060            .as_ref()
 8061            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8062        {
 8063            "Edit Hit Condition Breakpoint"
 8064        } else {
 8065            "Set Hit Condition Breakpoint"
 8066        };
 8067
 8068        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8069            "Unset Breakpoint"
 8070        } else {
 8071            "Set Breakpoint"
 8072        };
 8073
 8074        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8075
 8076        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8077            BreakpointState::Enabled => Some("Disable"),
 8078            BreakpointState::Disabled => Some("Enable"),
 8079        });
 8080
 8081        let (anchor, breakpoint) =
 8082            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8083
 8084        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8085            menu.on_blur_subscription(Subscription::new(|| {}))
 8086                .context(focus_handle)
 8087                .when(run_to_cursor, |this| {
 8088                    let weak_editor = weak_editor.clone();
 8089                    this.entry("Run to cursor", None, move |window, cx| {
 8090                        weak_editor
 8091                            .update(cx, |editor, cx| {
 8092                                editor.change_selections(
 8093                                    SelectionEffects::no_scroll(),
 8094                                    window,
 8095                                    cx,
 8096                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8097                                );
 8098                            })
 8099                            .ok();
 8100
 8101                        window.dispatch_action(Box::new(RunToCursor), cx);
 8102                    })
 8103                    .separator()
 8104                })
 8105                .when_some(toggle_state_msg, |this, msg| {
 8106                    this.entry(msg, None, {
 8107                        let weak_editor = weak_editor.clone();
 8108                        let breakpoint = breakpoint.clone();
 8109                        move |_window, cx| {
 8110                            weak_editor
 8111                                .update(cx, |this, cx| {
 8112                                    this.edit_breakpoint_at_anchor(
 8113                                        anchor,
 8114                                        breakpoint.as_ref().clone(),
 8115                                        BreakpointEditAction::InvertState,
 8116                                        cx,
 8117                                    );
 8118                                })
 8119                                .log_err();
 8120                        }
 8121                    })
 8122                })
 8123                .entry(set_breakpoint_msg, None, {
 8124                    let weak_editor = weak_editor.clone();
 8125                    let breakpoint = breakpoint.clone();
 8126                    move |_window, cx| {
 8127                        weak_editor
 8128                            .update(cx, |this, cx| {
 8129                                this.edit_breakpoint_at_anchor(
 8130                                    anchor,
 8131                                    breakpoint.as_ref().clone(),
 8132                                    BreakpointEditAction::Toggle,
 8133                                    cx,
 8134                                );
 8135                            })
 8136                            .log_err();
 8137                    }
 8138                })
 8139                .entry(log_breakpoint_msg, None, {
 8140                    let breakpoint = breakpoint.clone();
 8141                    let weak_editor = weak_editor.clone();
 8142                    move |window, cx| {
 8143                        weak_editor
 8144                            .update(cx, |this, cx| {
 8145                                this.add_edit_breakpoint_block(
 8146                                    anchor,
 8147                                    breakpoint.as_ref(),
 8148                                    BreakpointPromptEditAction::Log,
 8149                                    window,
 8150                                    cx,
 8151                                );
 8152                            })
 8153                            .log_err();
 8154                    }
 8155                })
 8156                .entry(condition_breakpoint_msg, None, {
 8157                    let breakpoint = breakpoint.clone();
 8158                    let weak_editor = weak_editor.clone();
 8159                    move |window, cx| {
 8160                        weak_editor
 8161                            .update(cx, |this, cx| {
 8162                                this.add_edit_breakpoint_block(
 8163                                    anchor,
 8164                                    breakpoint.as_ref(),
 8165                                    BreakpointPromptEditAction::Condition,
 8166                                    window,
 8167                                    cx,
 8168                                );
 8169                            })
 8170                            .log_err();
 8171                    }
 8172                })
 8173                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8174                    weak_editor
 8175                        .update(cx, |this, cx| {
 8176                            this.add_edit_breakpoint_block(
 8177                                anchor,
 8178                                breakpoint.as_ref(),
 8179                                BreakpointPromptEditAction::HitCondition,
 8180                                window,
 8181                                cx,
 8182                            );
 8183                        })
 8184                        .log_err();
 8185                })
 8186        })
 8187    }
 8188
 8189    fn render_breakpoint(
 8190        &self,
 8191        position: Anchor,
 8192        row: DisplayRow,
 8193        breakpoint: &Breakpoint,
 8194        state: Option<BreakpointSessionState>,
 8195        cx: &mut Context<Self>,
 8196    ) -> IconButton {
 8197        let is_rejected = state.is_some_and(|s| !s.verified);
 8198        // Is it a breakpoint that shows up when hovering over gutter?
 8199        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8200            (false, false),
 8201            |PhantomBreakpointIndicator {
 8202                 is_active,
 8203                 display_row,
 8204                 collides_with_existing_breakpoint,
 8205             }| {
 8206                (
 8207                    is_active && display_row == row,
 8208                    collides_with_existing_breakpoint,
 8209                )
 8210            },
 8211        );
 8212
 8213        let (color, icon) = {
 8214            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8215                (false, false) => ui::IconName::DebugBreakpoint,
 8216                (true, false) => ui::IconName::DebugLogBreakpoint,
 8217                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8218                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8219            };
 8220
 8221            let color = if is_phantom {
 8222                Color::Hint
 8223            } else if is_rejected {
 8224                Color::Disabled
 8225            } else {
 8226                Color::Debugger
 8227            };
 8228
 8229            (color, icon)
 8230        };
 8231
 8232        let breakpoint = Arc::from(breakpoint.clone());
 8233
 8234        let alt_as_text = gpui::Keystroke {
 8235            modifiers: Modifiers::secondary_key(),
 8236            ..Default::default()
 8237        };
 8238        let primary_action_text = if breakpoint.is_disabled() {
 8239            "Enable breakpoint"
 8240        } else if is_phantom && !collides_with_existing {
 8241            "Set breakpoint"
 8242        } else {
 8243            "Unset breakpoint"
 8244        };
 8245        let focus_handle = self.focus_handle.clone();
 8246
 8247        let meta = if is_rejected {
 8248            SharedString::from("No executable code is associated with this line.")
 8249        } else if collides_with_existing && !breakpoint.is_disabled() {
 8250            SharedString::from(format!(
 8251                "{alt_as_text}-click to disable,\nright-click for more options."
 8252            ))
 8253        } else {
 8254            SharedString::from("Right-click for more options.")
 8255        };
 8256        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8257            .icon_size(IconSize::XSmall)
 8258            .size(ui::ButtonSize::None)
 8259            .when(is_rejected, |this| {
 8260                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8261            })
 8262            .icon_color(color)
 8263            .style(ButtonStyle::Transparent)
 8264            .on_click(cx.listener({
 8265                move |editor, event: &ClickEvent, window, cx| {
 8266                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8267                        BreakpointEditAction::InvertState
 8268                    } else {
 8269                        BreakpointEditAction::Toggle
 8270                    };
 8271
 8272                    window.focus(&editor.focus_handle(cx));
 8273                    editor.edit_breakpoint_at_anchor(
 8274                        position,
 8275                        breakpoint.as_ref().clone(),
 8276                        edit_action,
 8277                        cx,
 8278                    );
 8279                }
 8280            }))
 8281            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8282                editor.set_breakpoint_context_menu(
 8283                    row,
 8284                    Some(position),
 8285                    event.position(),
 8286                    window,
 8287                    cx,
 8288                );
 8289            }))
 8290            .tooltip(move |_window, cx| {
 8291                Tooltip::with_meta_in(
 8292                    primary_action_text,
 8293                    Some(&ToggleBreakpoint),
 8294                    meta.clone(),
 8295                    &focus_handle,
 8296                    cx,
 8297                )
 8298            })
 8299    }
 8300
 8301    fn build_tasks_context(
 8302        project: &Entity<Project>,
 8303        buffer: &Entity<Buffer>,
 8304        buffer_row: u32,
 8305        tasks: &Arc<RunnableTasks>,
 8306        cx: &mut Context<Self>,
 8307    ) -> Task<Option<task::TaskContext>> {
 8308        let position = Point::new(buffer_row, tasks.column);
 8309        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8310        let location = Location {
 8311            buffer: buffer.clone(),
 8312            range: range_start..range_start,
 8313        };
 8314        // Fill in the environmental variables from the tree-sitter captures
 8315        let mut captured_task_variables = TaskVariables::default();
 8316        for (capture_name, value) in tasks.extra_variables.clone() {
 8317            captured_task_variables.insert(
 8318                task::VariableName::Custom(capture_name.into()),
 8319                value.clone(),
 8320            );
 8321        }
 8322        project.update(cx, |project, cx| {
 8323            project.task_store().update(cx, |task_store, cx| {
 8324                task_store.task_context_for_location(captured_task_variables, location, cx)
 8325            })
 8326        })
 8327    }
 8328
 8329    pub fn spawn_nearest_task(
 8330        &mut self,
 8331        action: &SpawnNearestTask,
 8332        window: &mut Window,
 8333        cx: &mut Context<Self>,
 8334    ) {
 8335        let Some((workspace, _)) = self.workspace.clone() else {
 8336            return;
 8337        };
 8338        let Some(project) = self.project.clone() else {
 8339            return;
 8340        };
 8341
 8342        // Try to find a closest, enclosing node using tree-sitter that has a task
 8343        let Some((buffer, buffer_row, tasks)) = self
 8344            .find_enclosing_node_task(cx)
 8345            // Or find the task that's closest in row-distance.
 8346            .or_else(|| self.find_closest_task(cx))
 8347        else {
 8348            return;
 8349        };
 8350
 8351        let reveal_strategy = action.reveal;
 8352        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8353        cx.spawn_in(window, async move |_, cx| {
 8354            let context = task_context.await?;
 8355            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8356
 8357            let resolved = &mut resolved_task.resolved;
 8358            resolved.reveal = reveal_strategy;
 8359
 8360            workspace
 8361                .update_in(cx, |workspace, window, cx| {
 8362                    workspace.schedule_resolved_task(
 8363                        task_source_kind,
 8364                        resolved_task,
 8365                        false,
 8366                        window,
 8367                        cx,
 8368                    );
 8369                })
 8370                .ok()
 8371        })
 8372        .detach();
 8373    }
 8374
 8375    fn find_closest_task(
 8376        &mut self,
 8377        cx: &mut Context<Self>,
 8378    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8379        let cursor_row = self
 8380            .selections
 8381            .newest_adjusted(&self.display_snapshot(cx))
 8382            .head()
 8383            .row;
 8384
 8385        let ((buffer_id, row), tasks) = self
 8386            .tasks
 8387            .iter()
 8388            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8389
 8390        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8391        let tasks = Arc::new(tasks.to_owned());
 8392        Some((buffer, *row, tasks))
 8393    }
 8394
 8395    fn find_enclosing_node_task(
 8396        &mut self,
 8397        cx: &mut Context<Self>,
 8398    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8399        let snapshot = self.buffer.read(cx).snapshot(cx);
 8400        let offset = self
 8401            .selections
 8402            .newest::<usize>(&self.display_snapshot(cx))
 8403            .head();
 8404        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8405        let buffer_id = excerpt.buffer().remote_id();
 8406
 8407        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8408        let mut cursor = layer.node().walk();
 8409
 8410        while cursor.goto_first_child_for_byte(offset).is_some() {
 8411            if cursor.node().end_byte() == offset {
 8412                cursor.goto_next_sibling();
 8413            }
 8414        }
 8415
 8416        // Ascend to the smallest ancestor that contains the range and has a task.
 8417        loop {
 8418            let node = cursor.node();
 8419            let node_range = node.byte_range();
 8420            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8421
 8422            // Check if this node contains our offset
 8423            if node_range.start <= offset && node_range.end >= offset {
 8424                // If it contains offset, check for task
 8425                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8426                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8427                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8428                }
 8429            }
 8430
 8431            if !cursor.goto_parent() {
 8432                break;
 8433            }
 8434        }
 8435        None
 8436    }
 8437
 8438    fn render_run_indicator(
 8439        &self,
 8440        _style: &EditorStyle,
 8441        is_active: bool,
 8442        row: DisplayRow,
 8443        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8444        cx: &mut Context<Self>,
 8445    ) -> IconButton {
 8446        let color = Color::Muted;
 8447        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8448
 8449        IconButton::new(
 8450            ("run_indicator", row.0 as usize),
 8451            ui::IconName::PlayOutlined,
 8452        )
 8453        .shape(ui::IconButtonShape::Square)
 8454        .icon_size(IconSize::XSmall)
 8455        .icon_color(color)
 8456        .toggle_state(is_active)
 8457        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8458            let quick_launch = match e {
 8459                ClickEvent::Keyboard(_) => true,
 8460                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8461            };
 8462
 8463            window.focus(&editor.focus_handle(cx));
 8464            editor.toggle_code_actions(
 8465                &ToggleCodeActions {
 8466                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8467                    quick_launch,
 8468                },
 8469                window,
 8470                cx,
 8471            );
 8472        }))
 8473        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8474            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8475        }))
 8476    }
 8477
 8478    pub fn context_menu_visible(&self) -> bool {
 8479        !self.edit_prediction_preview_is_active()
 8480            && self
 8481                .context_menu
 8482                .borrow()
 8483                .as_ref()
 8484                .is_some_and(|menu| menu.visible())
 8485    }
 8486
 8487    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8488        self.context_menu
 8489            .borrow()
 8490            .as_ref()
 8491            .map(|menu| menu.origin())
 8492    }
 8493
 8494    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8495        self.context_menu_options = Some(options);
 8496    }
 8497
 8498    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8499    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8500
 8501    fn render_edit_prediction_popover(
 8502        &mut self,
 8503        text_bounds: &Bounds<Pixels>,
 8504        content_origin: gpui::Point<Pixels>,
 8505        right_margin: Pixels,
 8506        editor_snapshot: &EditorSnapshot,
 8507        visible_row_range: Range<DisplayRow>,
 8508        scroll_top: ScrollOffset,
 8509        scroll_bottom: ScrollOffset,
 8510        line_layouts: &[LineWithInvisibles],
 8511        line_height: Pixels,
 8512        scroll_position: gpui::Point<ScrollOffset>,
 8513        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8514        newest_selection_head: Option<DisplayPoint>,
 8515        editor_width: Pixels,
 8516        style: &EditorStyle,
 8517        window: &mut Window,
 8518        cx: &mut App,
 8519    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8520        if self.mode().is_minimap() {
 8521            return None;
 8522        }
 8523        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8524
 8525        if self.edit_prediction_visible_in_cursor_popover(true) {
 8526            return None;
 8527        }
 8528
 8529        match &active_edit_prediction.completion {
 8530            EditPrediction::MoveWithin { target, .. } => {
 8531                let target_display_point = target.to_display_point(editor_snapshot);
 8532
 8533                if self.edit_prediction_requires_modifier() {
 8534                    if !self.edit_prediction_preview_is_active() {
 8535                        return None;
 8536                    }
 8537
 8538                    self.render_edit_prediction_modifier_jump_popover(
 8539                        text_bounds,
 8540                        content_origin,
 8541                        visible_row_range,
 8542                        line_layouts,
 8543                        line_height,
 8544                        scroll_pixel_position,
 8545                        newest_selection_head,
 8546                        target_display_point,
 8547                        window,
 8548                        cx,
 8549                    )
 8550                } else {
 8551                    self.render_edit_prediction_eager_jump_popover(
 8552                        text_bounds,
 8553                        content_origin,
 8554                        editor_snapshot,
 8555                        visible_row_range,
 8556                        scroll_top,
 8557                        scroll_bottom,
 8558                        line_height,
 8559                        scroll_pixel_position,
 8560                        target_display_point,
 8561                        editor_width,
 8562                        window,
 8563                        cx,
 8564                    )
 8565                }
 8566            }
 8567            EditPrediction::Edit {
 8568                display_mode: EditDisplayMode::Inline,
 8569                ..
 8570            } => None,
 8571            EditPrediction::Edit {
 8572                display_mode: EditDisplayMode::TabAccept,
 8573                edits,
 8574                ..
 8575            } => {
 8576                let range = &edits.first()?.0;
 8577                let target_display_point = range.end.to_display_point(editor_snapshot);
 8578
 8579                self.render_edit_prediction_end_of_line_popover(
 8580                    "Accept",
 8581                    editor_snapshot,
 8582                    visible_row_range,
 8583                    target_display_point,
 8584                    line_height,
 8585                    scroll_pixel_position,
 8586                    content_origin,
 8587                    editor_width,
 8588                    window,
 8589                    cx,
 8590                )
 8591            }
 8592            EditPrediction::Edit {
 8593                edits,
 8594                edit_preview,
 8595                display_mode: EditDisplayMode::DiffPopover,
 8596                snapshot,
 8597            } => self.render_edit_prediction_diff_popover(
 8598                text_bounds,
 8599                content_origin,
 8600                right_margin,
 8601                editor_snapshot,
 8602                visible_row_range,
 8603                line_layouts,
 8604                line_height,
 8605                scroll_position,
 8606                scroll_pixel_position,
 8607                newest_selection_head,
 8608                editor_width,
 8609                style,
 8610                edits,
 8611                edit_preview,
 8612                snapshot,
 8613                window,
 8614                cx,
 8615            ),
 8616            EditPrediction::MoveOutside { snapshot, .. } => {
 8617                let file_name = snapshot
 8618                    .file()
 8619                    .map(|file| file.file_name(cx))
 8620                    .unwrap_or("untitled");
 8621                let mut element = self
 8622                    .render_edit_prediction_line_popover(
 8623                        format!("Jump to {file_name}"),
 8624                        Some(IconName::ZedPredict),
 8625                        window,
 8626                        cx,
 8627                    )
 8628                    .into_any();
 8629
 8630                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8631                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8632                let origin_y = text_bounds.size.height - size.height - px(30.);
 8633                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8634                element.prepaint_at(origin, window, cx);
 8635
 8636                Some((element, origin))
 8637            }
 8638        }
 8639    }
 8640
 8641    fn render_edit_prediction_modifier_jump_popover(
 8642        &mut self,
 8643        text_bounds: &Bounds<Pixels>,
 8644        content_origin: gpui::Point<Pixels>,
 8645        visible_row_range: Range<DisplayRow>,
 8646        line_layouts: &[LineWithInvisibles],
 8647        line_height: Pixels,
 8648        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8649        newest_selection_head: Option<DisplayPoint>,
 8650        target_display_point: DisplayPoint,
 8651        window: &mut Window,
 8652        cx: &mut App,
 8653    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8654        let scrolled_content_origin =
 8655            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8656
 8657        const SCROLL_PADDING_Y: Pixels = px(12.);
 8658
 8659        if target_display_point.row() < visible_row_range.start {
 8660            return self.render_edit_prediction_scroll_popover(
 8661                |_| SCROLL_PADDING_Y,
 8662                IconName::ArrowUp,
 8663                visible_row_range,
 8664                line_layouts,
 8665                newest_selection_head,
 8666                scrolled_content_origin,
 8667                window,
 8668                cx,
 8669            );
 8670        } else if target_display_point.row() >= visible_row_range.end {
 8671            return self.render_edit_prediction_scroll_popover(
 8672                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8673                IconName::ArrowDown,
 8674                visible_row_range,
 8675                line_layouts,
 8676                newest_selection_head,
 8677                scrolled_content_origin,
 8678                window,
 8679                cx,
 8680            );
 8681        }
 8682
 8683        const POLE_WIDTH: Pixels = px(2.);
 8684
 8685        let line_layout =
 8686            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8687        let target_column = target_display_point.column() as usize;
 8688
 8689        let target_x = line_layout.x_for_index(target_column);
 8690        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8691            - scroll_pixel_position.y;
 8692
 8693        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8694
 8695        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8696        border_color.l += 0.001;
 8697
 8698        let mut element = v_flex()
 8699            .items_end()
 8700            .when(flag_on_right, |el| el.items_start())
 8701            .child(if flag_on_right {
 8702                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8703                    .rounded_bl(px(0.))
 8704                    .rounded_tl(px(0.))
 8705                    .border_l_2()
 8706                    .border_color(border_color)
 8707            } else {
 8708                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8709                    .rounded_br(px(0.))
 8710                    .rounded_tr(px(0.))
 8711                    .border_r_2()
 8712                    .border_color(border_color)
 8713            })
 8714            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8715            .into_any();
 8716
 8717        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8718
 8719        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8720            - point(
 8721                if flag_on_right {
 8722                    POLE_WIDTH
 8723                } else {
 8724                    size.width - POLE_WIDTH
 8725                },
 8726                size.height - line_height,
 8727            );
 8728
 8729        origin.x = origin.x.max(content_origin.x);
 8730
 8731        element.prepaint_at(origin, window, cx);
 8732
 8733        Some((element, origin))
 8734    }
 8735
 8736    fn render_edit_prediction_scroll_popover(
 8737        &mut self,
 8738        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8739        scroll_icon: IconName,
 8740        visible_row_range: Range<DisplayRow>,
 8741        line_layouts: &[LineWithInvisibles],
 8742        newest_selection_head: Option<DisplayPoint>,
 8743        scrolled_content_origin: gpui::Point<Pixels>,
 8744        window: &mut Window,
 8745        cx: &mut App,
 8746    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8747        let mut element = self
 8748            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8749            .into_any();
 8750
 8751        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8752
 8753        let cursor = newest_selection_head?;
 8754        let cursor_row_layout =
 8755            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8756        let cursor_column = cursor.column() as usize;
 8757
 8758        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8759
 8760        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8761
 8762        element.prepaint_at(origin, window, cx);
 8763        Some((element, origin))
 8764    }
 8765
 8766    fn render_edit_prediction_eager_jump_popover(
 8767        &mut self,
 8768        text_bounds: &Bounds<Pixels>,
 8769        content_origin: gpui::Point<Pixels>,
 8770        editor_snapshot: &EditorSnapshot,
 8771        visible_row_range: Range<DisplayRow>,
 8772        scroll_top: ScrollOffset,
 8773        scroll_bottom: ScrollOffset,
 8774        line_height: Pixels,
 8775        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8776        target_display_point: DisplayPoint,
 8777        editor_width: Pixels,
 8778        window: &mut Window,
 8779        cx: &mut App,
 8780    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8781        if target_display_point.row().as_f64() < scroll_top {
 8782            let mut element = self
 8783                .render_edit_prediction_line_popover(
 8784                    "Jump to Edit",
 8785                    Some(IconName::ArrowUp),
 8786                    window,
 8787                    cx,
 8788                )
 8789                .into_any();
 8790
 8791            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8792            let offset = point(
 8793                (text_bounds.size.width - size.width) / 2.,
 8794                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8795            );
 8796
 8797            let origin = text_bounds.origin + offset;
 8798            element.prepaint_at(origin, window, cx);
 8799            Some((element, origin))
 8800        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8801            let mut element = self
 8802                .render_edit_prediction_line_popover(
 8803                    "Jump to Edit",
 8804                    Some(IconName::ArrowDown),
 8805                    window,
 8806                    cx,
 8807                )
 8808                .into_any();
 8809
 8810            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8811            let offset = point(
 8812                (text_bounds.size.width - size.width) / 2.,
 8813                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8814            );
 8815
 8816            let origin = text_bounds.origin + offset;
 8817            element.prepaint_at(origin, window, cx);
 8818            Some((element, origin))
 8819        } else {
 8820            self.render_edit_prediction_end_of_line_popover(
 8821                "Jump to Edit",
 8822                editor_snapshot,
 8823                visible_row_range,
 8824                target_display_point,
 8825                line_height,
 8826                scroll_pixel_position,
 8827                content_origin,
 8828                editor_width,
 8829                window,
 8830                cx,
 8831            )
 8832        }
 8833    }
 8834
 8835    fn render_edit_prediction_end_of_line_popover(
 8836        self: &mut Editor,
 8837        label: &'static str,
 8838        editor_snapshot: &EditorSnapshot,
 8839        visible_row_range: Range<DisplayRow>,
 8840        target_display_point: DisplayPoint,
 8841        line_height: Pixels,
 8842        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8843        content_origin: gpui::Point<Pixels>,
 8844        editor_width: Pixels,
 8845        window: &mut Window,
 8846        cx: &mut App,
 8847    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8848        let target_line_end = DisplayPoint::new(
 8849            target_display_point.row(),
 8850            editor_snapshot.line_len(target_display_point.row()),
 8851        );
 8852
 8853        let mut element = self
 8854            .render_edit_prediction_line_popover(label, None, window, cx)
 8855            .into_any();
 8856
 8857        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8858
 8859        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8860
 8861        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8862        let mut origin = start_point
 8863            + line_origin
 8864            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8865        origin.x = origin.x.max(content_origin.x);
 8866
 8867        let max_x = content_origin.x + editor_width - size.width;
 8868
 8869        if origin.x > max_x {
 8870            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8871
 8872            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8873                origin.y += offset;
 8874                IconName::ArrowUp
 8875            } else {
 8876                origin.y -= offset;
 8877                IconName::ArrowDown
 8878            };
 8879
 8880            element = self
 8881                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 8882                .into_any();
 8883
 8884            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8885
 8886            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8887        }
 8888
 8889        element.prepaint_at(origin, window, cx);
 8890        Some((element, origin))
 8891    }
 8892
 8893    fn render_edit_prediction_diff_popover(
 8894        self: &Editor,
 8895        text_bounds: &Bounds<Pixels>,
 8896        content_origin: gpui::Point<Pixels>,
 8897        right_margin: Pixels,
 8898        editor_snapshot: &EditorSnapshot,
 8899        visible_row_range: Range<DisplayRow>,
 8900        line_layouts: &[LineWithInvisibles],
 8901        line_height: Pixels,
 8902        scroll_position: gpui::Point<ScrollOffset>,
 8903        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8904        newest_selection_head: Option<DisplayPoint>,
 8905        editor_width: Pixels,
 8906        style: &EditorStyle,
 8907        edits: &Vec<(Range<Anchor>, String)>,
 8908        edit_preview: &Option<language::EditPreview>,
 8909        snapshot: &language::BufferSnapshot,
 8910        window: &mut Window,
 8911        cx: &mut App,
 8912    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8913        let edit_start = edits
 8914            .first()
 8915            .unwrap()
 8916            .0
 8917            .start
 8918            .to_display_point(editor_snapshot);
 8919        let edit_end = edits
 8920            .last()
 8921            .unwrap()
 8922            .0
 8923            .end
 8924            .to_display_point(editor_snapshot);
 8925
 8926        let is_visible = visible_row_range.contains(&edit_start.row())
 8927            || visible_row_range.contains(&edit_end.row());
 8928        if !is_visible {
 8929            return None;
 8930        }
 8931
 8932        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8933            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8934        } else {
 8935            // Fallback for providers without edit_preview
 8936            crate::edit_prediction_fallback_text(edits, cx)
 8937        };
 8938
 8939        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8940        let line_count = highlighted_edits.text.lines().count();
 8941
 8942        const BORDER_WIDTH: Pixels = px(1.);
 8943
 8944        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8945        let has_keybind = keybind.is_some();
 8946
 8947        let mut element = h_flex()
 8948            .items_start()
 8949            .child(
 8950                h_flex()
 8951                    .bg(cx.theme().colors().editor_background)
 8952                    .border(BORDER_WIDTH)
 8953                    .shadow_xs()
 8954                    .border_color(cx.theme().colors().border)
 8955                    .rounded_l_lg()
 8956                    .when(line_count > 1, |el| el.rounded_br_lg())
 8957                    .pr_1()
 8958                    .child(styled_text),
 8959            )
 8960            .child(
 8961                h_flex()
 8962                    .h(line_height + BORDER_WIDTH * 2.)
 8963                    .px_1p5()
 8964                    .gap_1()
 8965                    // Workaround: For some reason, there's a gap if we don't do this
 8966                    .ml(-BORDER_WIDTH)
 8967                    .shadow(vec![gpui::BoxShadow {
 8968                        color: gpui::black().opacity(0.05),
 8969                        offset: point(px(1.), px(1.)),
 8970                        blur_radius: px(2.),
 8971                        spread_radius: px(0.),
 8972                    }])
 8973                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8974                    .border(BORDER_WIDTH)
 8975                    .border_color(cx.theme().colors().border)
 8976                    .rounded_r_lg()
 8977                    .id("edit_prediction_diff_popover_keybind")
 8978                    .when(!has_keybind, |el| {
 8979                        let status_colors = cx.theme().status();
 8980
 8981                        el.bg(status_colors.error_background)
 8982                            .border_color(status_colors.error.opacity(0.6))
 8983                            .child(Icon::new(IconName::Info).color(Color::Error))
 8984                            .cursor_default()
 8985                            .hoverable_tooltip(move |_window, cx| {
 8986                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8987                            })
 8988                    })
 8989                    .children(keybind),
 8990            )
 8991            .into_any();
 8992
 8993        let longest_row =
 8994            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8995        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8996            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8997        } else {
 8998            layout_line(
 8999                longest_row,
 9000                editor_snapshot,
 9001                style,
 9002                editor_width,
 9003                |_| false,
 9004                window,
 9005                cx,
 9006            )
 9007            .width
 9008        };
 9009
 9010        let viewport_bounds =
 9011            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9012                right: -right_margin,
 9013                ..Default::default()
 9014            });
 9015
 9016        let x_after_longest = Pixels::from(
 9017            ScrollPixelOffset::from(
 9018                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9019            ) - scroll_pixel_position.x,
 9020        );
 9021
 9022        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9023
 9024        // Fully visible if it can be displayed within the window (allow overlapping other
 9025        // panes). However, this is only allowed if the popover starts within text_bounds.
 9026        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9027            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9028
 9029        let mut origin = if can_position_to_the_right {
 9030            point(
 9031                x_after_longest,
 9032                text_bounds.origin.y
 9033                    + Pixels::from(
 9034                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9035                            - scroll_pixel_position.y,
 9036                    ),
 9037            )
 9038        } else {
 9039            let cursor_row = newest_selection_head.map(|head| head.row());
 9040            let above_edit = edit_start
 9041                .row()
 9042                .0
 9043                .checked_sub(line_count as u32)
 9044                .map(DisplayRow);
 9045            let below_edit = Some(edit_end.row() + 1);
 9046            let above_cursor =
 9047                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9048            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9049
 9050            // Place the edit popover adjacent to the edit if there is a location
 9051            // available that is onscreen and does not obscure the cursor. Otherwise,
 9052            // place it adjacent to the cursor.
 9053            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9054                .into_iter()
 9055                .flatten()
 9056                .find(|&start_row| {
 9057                    let end_row = start_row + line_count as u32;
 9058                    visible_row_range.contains(&start_row)
 9059                        && visible_row_range.contains(&end_row)
 9060                        && cursor_row
 9061                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9062                })?;
 9063
 9064            content_origin
 9065                + point(
 9066                    Pixels::from(-scroll_pixel_position.x),
 9067                    Pixels::from(
 9068                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9069                    ),
 9070                )
 9071        };
 9072
 9073        origin.x -= BORDER_WIDTH;
 9074
 9075        window.defer_draw(element, origin, 1);
 9076
 9077        // Do not return an element, since it will already be drawn due to defer_draw.
 9078        None
 9079    }
 9080
 9081    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9082        px(30.)
 9083    }
 9084
 9085    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9086        if self.read_only(cx) {
 9087            cx.theme().players().read_only()
 9088        } else {
 9089            self.style.as_ref().unwrap().local_player
 9090        }
 9091    }
 9092
 9093    fn render_edit_prediction_accept_keybind(
 9094        &self,
 9095        window: &mut Window,
 9096        cx: &mut App,
 9097    ) -> Option<AnyElement> {
 9098        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9099        let accept_keystroke = accept_binding.keystroke()?;
 9100
 9101        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9102
 9103        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9104            Color::Accent
 9105        } else {
 9106            Color::Muted
 9107        };
 9108
 9109        h_flex()
 9110            .px_0p5()
 9111            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9112            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9113            .text_size(TextSize::XSmall.rems(cx))
 9114            .child(h_flex().children(ui::render_modifiers(
 9115                accept_keystroke.modifiers(),
 9116                PlatformStyle::platform(),
 9117                Some(modifiers_color),
 9118                Some(IconSize::XSmall.rems().into()),
 9119                true,
 9120            )))
 9121            .when(is_platform_style_mac, |parent| {
 9122                parent.child(accept_keystroke.key().to_string())
 9123            })
 9124            .when(!is_platform_style_mac, |parent| {
 9125                parent.child(
 9126                    Key::new(
 9127                        util::capitalize(accept_keystroke.key()),
 9128                        Some(Color::Default),
 9129                    )
 9130                    .size(Some(IconSize::XSmall.rems().into())),
 9131                )
 9132            })
 9133            .into_any()
 9134            .into()
 9135    }
 9136
 9137    fn render_edit_prediction_line_popover(
 9138        &self,
 9139        label: impl Into<SharedString>,
 9140        icon: Option<IconName>,
 9141        window: &mut Window,
 9142        cx: &mut App,
 9143    ) -> Stateful<Div> {
 9144        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9145
 9146        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9147        let has_keybind = keybind.is_some();
 9148
 9149        h_flex()
 9150            .id("ep-line-popover")
 9151            .py_0p5()
 9152            .pl_1()
 9153            .pr(padding_right)
 9154            .gap_1()
 9155            .rounded_md()
 9156            .border_1()
 9157            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9158            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9159            .shadow_xs()
 9160            .when(!has_keybind, |el| {
 9161                let status_colors = cx.theme().status();
 9162
 9163                el.bg(status_colors.error_background)
 9164                    .border_color(status_colors.error.opacity(0.6))
 9165                    .pl_2()
 9166                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9167                    .cursor_default()
 9168                    .hoverable_tooltip(move |_window, cx| {
 9169                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9170                    })
 9171            })
 9172            .children(keybind)
 9173            .child(
 9174                Label::new(label)
 9175                    .size(LabelSize::Small)
 9176                    .when(!has_keybind, |el| {
 9177                        el.color(cx.theme().status().error.into()).strikethrough()
 9178                    }),
 9179            )
 9180            .when(!has_keybind, |el| {
 9181                el.child(
 9182                    h_flex().ml_1().child(
 9183                        Icon::new(IconName::Info)
 9184                            .size(IconSize::Small)
 9185                            .color(cx.theme().status().error.into()),
 9186                    ),
 9187                )
 9188            })
 9189            .when_some(icon, |element, icon| {
 9190                element.child(
 9191                    div()
 9192                        .mt(px(1.5))
 9193                        .child(Icon::new(icon).size(IconSize::Small)),
 9194                )
 9195            })
 9196    }
 9197
 9198    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9199        let accent_color = cx.theme().colors().text_accent;
 9200        let editor_bg_color = cx.theme().colors().editor_background;
 9201        editor_bg_color.blend(accent_color.opacity(0.1))
 9202    }
 9203
 9204    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9205        let accent_color = cx.theme().colors().text_accent;
 9206        let editor_bg_color = cx.theme().colors().editor_background;
 9207        editor_bg_color.blend(accent_color.opacity(0.6))
 9208    }
 9209    fn get_prediction_provider_icon_name(
 9210        provider: &Option<RegisteredEditPredictionProvider>,
 9211    ) -> IconName {
 9212        match provider {
 9213            Some(provider) => match provider.provider.name() {
 9214                "copilot" => IconName::Copilot,
 9215                "supermaven" => IconName::Supermaven,
 9216                _ => IconName::ZedPredict,
 9217            },
 9218            None => IconName::ZedPredict,
 9219        }
 9220    }
 9221
 9222    fn render_edit_prediction_cursor_popover(
 9223        &self,
 9224        min_width: Pixels,
 9225        max_width: Pixels,
 9226        cursor_point: Point,
 9227        style: &EditorStyle,
 9228        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9229        _window: &Window,
 9230        cx: &mut Context<Editor>,
 9231    ) -> Option<AnyElement> {
 9232        let provider = self.edit_prediction_provider.as_ref()?;
 9233        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9234
 9235        let is_refreshing = provider.provider.is_refreshing(cx);
 9236
 9237        fn pending_completion_container(icon: IconName) -> Div {
 9238            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9239        }
 9240
 9241        let completion = match &self.active_edit_prediction {
 9242            Some(prediction) => {
 9243                if !self.has_visible_completions_menu() {
 9244                    const RADIUS: Pixels = px(6.);
 9245                    const BORDER_WIDTH: Pixels = px(1.);
 9246
 9247                    return Some(
 9248                        h_flex()
 9249                            .elevation_2(cx)
 9250                            .border(BORDER_WIDTH)
 9251                            .border_color(cx.theme().colors().border)
 9252                            .when(accept_keystroke.is_none(), |el| {
 9253                                el.border_color(cx.theme().status().error)
 9254                            })
 9255                            .rounded(RADIUS)
 9256                            .rounded_tl(px(0.))
 9257                            .overflow_hidden()
 9258                            .child(div().px_1p5().child(match &prediction.completion {
 9259                                EditPrediction::MoveWithin { target, snapshot } => {
 9260                                    use text::ToPoint as _;
 9261                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9262                                    {
 9263                                        Icon::new(IconName::ZedPredictDown)
 9264                                    } else {
 9265                                        Icon::new(IconName::ZedPredictUp)
 9266                                    }
 9267                                }
 9268                                EditPrediction::MoveOutside { .. } => {
 9269                                    // TODO [zeta2] custom icon for external jump?
 9270                                    Icon::new(provider_icon)
 9271                                }
 9272                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9273                            }))
 9274                            .child(
 9275                                h_flex()
 9276                                    .gap_1()
 9277                                    .py_1()
 9278                                    .px_2()
 9279                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9280                                    .border_l_1()
 9281                                    .border_color(cx.theme().colors().border)
 9282                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9283                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9284                                        el.child(
 9285                                            Label::new("Hold")
 9286                                                .size(LabelSize::Small)
 9287                                                .when(accept_keystroke.is_none(), |el| {
 9288                                                    el.strikethrough()
 9289                                                })
 9290                                                .line_height_style(LineHeightStyle::UiLabel),
 9291                                        )
 9292                                    })
 9293                                    .id("edit_prediction_cursor_popover_keybind")
 9294                                    .when(accept_keystroke.is_none(), |el| {
 9295                                        let status_colors = cx.theme().status();
 9296
 9297                                        el.bg(status_colors.error_background)
 9298                                            .border_color(status_colors.error.opacity(0.6))
 9299                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9300                                            .cursor_default()
 9301                                            .hoverable_tooltip(move |_window, cx| {
 9302                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9303                                                    .into()
 9304                                            })
 9305                                    })
 9306                                    .when_some(
 9307                                        accept_keystroke.as_ref(),
 9308                                        |el, accept_keystroke| {
 9309                                            el.child(h_flex().children(ui::render_modifiers(
 9310                                                accept_keystroke.modifiers(),
 9311                                                PlatformStyle::platform(),
 9312                                                Some(Color::Default),
 9313                                                Some(IconSize::XSmall.rems().into()),
 9314                                                false,
 9315                                            )))
 9316                                        },
 9317                                    ),
 9318                            )
 9319                            .into_any(),
 9320                    );
 9321                }
 9322
 9323                self.render_edit_prediction_cursor_popover_preview(
 9324                    prediction,
 9325                    cursor_point,
 9326                    style,
 9327                    cx,
 9328                )?
 9329            }
 9330
 9331            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9332                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9333                    stale_completion,
 9334                    cursor_point,
 9335                    style,
 9336                    cx,
 9337                )?,
 9338
 9339                None => pending_completion_container(provider_icon)
 9340                    .child(Label::new("...").size(LabelSize::Small)),
 9341            },
 9342
 9343            None => pending_completion_container(provider_icon)
 9344                .child(Label::new("...").size(LabelSize::Small)),
 9345        };
 9346
 9347        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9348            completion
 9349                .with_animation(
 9350                    "loading-completion",
 9351                    Animation::new(Duration::from_secs(2))
 9352                        .repeat()
 9353                        .with_easing(pulsating_between(0.4, 0.8)),
 9354                    |label, delta| label.opacity(delta),
 9355                )
 9356                .into_any_element()
 9357        } else {
 9358            completion.into_any_element()
 9359        };
 9360
 9361        let has_completion = self.active_edit_prediction.is_some();
 9362
 9363        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9364        Some(
 9365            h_flex()
 9366                .min_w(min_width)
 9367                .max_w(max_width)
 9368                .flex_1()
 9369                .elevation_2(cx)
 9370                .border_color(cx.theme().colors().border)
 9371                .child(
 9372                    div()
 9373                        .flex_1()
 9374                        .py_1()
 9375                        .px_2()
 9376                        .overflow_hidden()
 9377                        .child(completion),
 9378                )
 9379                .when_some(accept_keystroke, |el, accept_keystroke| {
 9380                    if !accept_keystroke.modifiers().modified() {
 9381                        return el;
 9382                    }
 9383
 9384                    el.child(
 9385                        h_flex()
 9386                            .h_full()
 9387                            .border_l_1()
 9388                            .rounded_r_lg()
 9389                            .border_color(cx.theme().colors().border)
 9390                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9391                            .gap_1()
 9392                            .py_1()
 9393                            .px_2()
 9394                            .child(
 9395                                h_flex()
 9396                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9397                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9398                                    .child(h_flex().children(ui::render_modifiers(
 9399                                        accept_keystroke.modifiers(),
 9400                                        PlatformStyle::platform(),
 9401                                        Some(if !has_completion {
 9402                                            Color::Muted
 9403                                        } else {
 9404                                            Color::Default
 9405                                        }),
 9406                                        None,
 9407                                        false,
 9408                                    ))),
 9409                            )
 9410                            .child(Label::new("Preview").into_any_element())
 9411                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9412                    )
 9413                })
 9414                .into_any(),
 9415        )
 9416    }
 9417
 9418    fn render_edit_prediction_cursor_popover_preview(
 9419        &self,
 9420        completion: &EditPredictionState,
 9421        cursor_point: Point,
 9422        style: &EditorStyle,
 9423        cx: &mut Context<Editor>,
 9424    ) -> Option<Div> {
 9425        use text::ToPoint as _;
 9426
 9427        fn render_relative_row_jump(
 9428            prefix: impl Into<String>,
 9429            current_row: u32,
 9430            target_row: u32,
 9431        ) -> Div {
 9432            let (row_diff, arrow) = if target_row < current_row {
 9433                (current_row - target_row, IconName::ArrowUp)
 9434            } else {
 9435                (target_row - current_row, IconName::ArrowDown)
 9436            };
 9437
 9438            h_flex()
 9439                .child(
 9440                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9441                        .color(Color::Muted)
 9442                        .size(LabelSize::Small),
 9443                )
 9444                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9445        }
 9446
 9447        let supports_jump = self
 9448            .edit_prediction_provider
 9449            .as_ref()
 9450            .map(|provider| provider.provider.supports_jump_to_edit())
 9451            .unwrap_or(true);
 9452
 9453        match &completion.completion {
 9454            EditPrediction::MoveWithin {
 9455                target, snapshot, ..
 9456            } => {
 9457                if !supports_jump {
 9458                    return None;
 9459                }
 9460
 9461                Some(
 9462                    h_flex()
 9463                        .px_2()
 9464                        .gap_2()
 9465                        .flex_1()
 9466                        .child(
 9467                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9468                                Icon::new(IconName::ZedPredictDown)
 9469                            } else {
 9470                                Icon::new(IconName::ZedPredictUp)
 9471                            },
 9472                        )
 9473                        .child(Label::new("Jump to Edit")),
 9474                )
 9475            }
 9476            EditPrediction::MoveOutside { snapshot, .. } => {
 9477                let file_name = snapshot
 9478                    .file()
 9479                    .map(|file| file.file_name(cx))
 9480                    .unwrap_or("untitled");
 9481                Some(
 9482                    h_flex()
 9483                        .px_2()
 9484                        .gap_2()
 9485                        .flex_1()
 9486                        .child(Icon::new(IconName::ZedPredict))
 9487                        .child(Label::new(format!("Jump to {file_name}"))),
 9488                )
 9489            }
 9490            EditPrediction::Edit {
 9491                edits,
 9492                edit_preview,
 9493                snapshot,
 9494                display_mode: _,
 9495            } => {
 9496                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9497
 9498                let (highlighted_edits, has_more_lines) =
 9499                    if let Some(edit_preview) = edit_preview.as_ref() {
 9500                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9501                            .first_line_preview()
 9502                    } else {
 9503                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9504                    };
 9505
 9506                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9507                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9508
 9509                let preview = h_flex()
 9510                    .gap_1()
 9511                    .min_w_16()
 9512                    .child(styled_text)
 9513                    .when(has_more_lines, |parent| parent.child(""));
 9514
 9515                let left = if supports_jump && first_edit_row != cursor_point.row {
 9516                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9517                        .into_any_element()
 9518                } else {
 9519                    let icon_name =
 9520                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9521                    Icon::new(icon_name).into_any_element()
 9522                };
 9523
 9524                Some(
 9525                    h_flex()
 9526                        .h_full()
 9527                        .flex_1()
 9528                        .gap_2()
 9529                        .pr_1()
 9530                        .overflow_x_hidden()
 9531                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9532                        .child(left)
 9533                        .child(preview),
 9534                )
 9535            }
 9536        }
 9537    }
 9538
 9539    pub fn render_context_menu(
 9540        &self,
 9541        style: &EditorStyle,
 9542        max_height_in_lines: u32,
 9543        window: &mut Window,
 9544        cx: &mut Context<Editor>,
 9545    ) -> Option<AnyElement> {
 9546        let menu = self.context_menu.borrow();
 9547        let menu = menu.as_ref()?;
 9548        if !menu.visible() {
 9549            return None;
 9550        };
 9551        Some(menu.render(style, max_height_in_lines, window, cx))
 9552    }
 9553
 9554    fn render_context_menu_aside(
 9555        &mut self,
 9556        max_size: Size<Pixels>,
 9557        window: &mut Window,
 9558        cx: &mut Context<Editor>,
 9559    ) -> Option<AnyElement> {
 9560        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9561            if menu.visible() {
 9562                menu.render_aside(max_size, window, cx)
 9563            } else {
 9564                None
 9565            }
 9566        })
 9567    }
 9568
 9569    fn hide_context_menu(
 9570        &mut self,
 9571        window: &mut Window,
 9572        cx: &mut Context<Self>,
 9573    ) -> Option<CodeContextMenu> {
 9574        cx.notify();
 9575        self.completion_tasks.clear();
 9576        let context_menu = self.context_menu.borrow_mut().take();
 9577        self.stale_edit_prediction_in_menu.take();
 9578        self.update_visible_edit_prediction(window, cx);
 9579        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9580            && let Some(completion_provider) = &self.completion_provider
 9581        {
 9582            completion_provider.selection_changed(None, window, cx);
 9583        }
 9584        context_menu
 9585    }
 9586
 9587    fn show_snippet_choices(
 9588        &mut self,
 9589        choices: &Vec<String>,
 9590        selection: Range<Anchor>,
 9591        cx: &mut Context<Self>,
 9592    ) {
 9593        let Some((_, buffer, _)) = self
 9594            .buffer()
 9595            .read(cx)
 9596            .excerpt_containing(selection.start, cx)
 9597        else {
 9598            return;
 9599        };
 9600        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9601        else {
 9602            return;
 9603        };
 9604        if buffer != end_buffer {
 9605            log::error!("expected anchor range to have matching buffer IDs");
 9606            return;
 9607        }
 9608
 9609        let id = post_inc(&mut self.next_completion_id);
 9610        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9611        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9612            CompletionsMenu::new_snippet_choices(
 9613                id,
 9614                true,
 9615                choices,
 9616                selection,
 9617                buffer,
 9618                snippet_sort_order,
 9619            ),
 9620        ));
 9621    }
 9622
 9623    pub fn insert_snippet(
 9624        &mut self,
 9625        insertion_ranges: &[Range<usize>],
 9626        snippet: Snippet,
 9627        window: &mut Window,
 9628        cx: &mut Context<Self>,
 9629    ) -> Result<()> {
 9630        struct Tabstop<T> {
 9631            is_end_tabstop: bool,
 9632            ranges: Vec<Range<T>>,
 9633            choices: Option<Vec<String>>,
 9634        }
 9635
 9636        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9637            let snippet_text: Arc<str> = snippet.text.clone().into();
 9638            let edits = insertion_ranges
 9639                .iter()
 9640                .cloned()
 9641                .map(|range| (range, snippet_text.clone()));
 9642            let autoindent_mode = AutoindentMode::Block {
 9643                original_indent_columns: Vec::new(),
 9644            };
 9645            buffer.edit(edits, Some(autoindent_mode), cx);
 9646
 9647            let snapshot = &*buffer.read(cx);
 9648            let snippet = &snippet;
 9649            snippet
 9650                .tabstops
 9651                .iter()
 9652                .map(|tabstop| {
 9653                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9654                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9655                    });
 9656                    let mut tabstop_ranges = tabstop
 9657                        .ranges
 9658                        .iter()
 9659                        .flat_map(|tabstop_range| {
 9660                            let mut delta = 0_isize;
 9661                            insertion_ranges.iter().map(move |insertion_range| {
 9662                                let insertion_start = insertion_range.start as isize + delta;
 9663                                delta +=
 9664                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9665
 9666                                let start = ((insertion_start + tabstop_range.start) as usize)
 9667                                    .min(snapshot.len());
 9668                                let end = ((insertion_start + tabstop_range.end) as usize)
 9669                                    .min(snapshot.len());
 9670                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9671                            })
 9672                        })
 9673                        .collect::<Vec<_>>();
 9674                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9675
 9676                    Tabstop {
 9677                        is_end_tabstop,
 9678                        ranges: tabstop_ranges,
 9679                        choices: tabstop.choices.clone(),
 9680                    }
 9681                })
 9682                .collect::<Vec<_>>()
 9683        });
 9684        if let Some(tabstop) = tabstops.first() {
 9685            self.change_selections(Default::default(), window, cx, |s| {
 9686                // Reverse order so that the first range is the newest created selection.
 9687                // Completions will use it and autoscroll will prioritize it.
 9688                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9689            });
 9690
 9691            if let Some(choices) = &tabstop.choices
 9692                && let Some(selection) = tabstop.ranges.first()
 9693            {
 9694                self.show_snippet_choices(choices, selection.clone(), cx)
 9695            }
 9696
 9697            // If we're already at the last tabstop and it's at the end of the snippet,
 9698            // we're done, we don't need to keep the state around.
 9699            if !tabstop.is_end_tabstop {
 9700                let choices = tabstops
 9701                    .iter()
 9702                    .map(|tabstop| tabstop.choices.clone())
 9703                    .collect();
 9704
 9705                let ranges = tabstops
 9706                    .into_iter()
 9707                    .map(|tabstop| tabstop.ranges)
 9708                    .collect::<Vec<_>>();
 9709
 9710                self.snippet_stack.push(SnippetState {
 9711                    active_index: 0,
 9712                    ranges,
 9713                    choices,
 9714                });
 9715            }
 9716
 9717            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9718            if self.autoclose_regions.is_empty() {
 9719                let snapshot = self.buffer.read(cx).snapshot(cx);
 9720                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9721                    let selection_head = selection.head();
 9722                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9723                        continue;
 9724                    };
 9725
 9726                    let mut bracket_pair = None;
 9727                    let max_lookup_length = scope
 9728                        .brackets()
 9729                        .map(|(pair, _)| {
 9730                            pair.start
 9731                                .as_str()
 9732                                .chars()
 9733                                .count()
 9734                                .max(pair.end.as_str().chars().count())
 9735                        })
 9736                        .max();
 9737                    if let Some(max_lookup_length) = max_lookup_length {
 9738                        let next_text = snapshot
 9739                            .chars_at(selection_head)
 9740                            .take(max_lookup_length)
 9741                            .collect::<String>();
 9742                        let prev_text = snapshot
 9743                            .reversed_chars_at(selection_head)
 9744                            .take(max_lookup_length)
 9745                            .collect::<String>();
 9746
 9747                        for (pair, enabled) in scope.brackets() {
 9748                            if enabled
 9749                                && pair.close
 9750                                && prev_text.starts_with(pair.start.as_str())
 9751                                && next_text.starts_with(pair.end.as_str())
 9752                            {
 9753                                bracket_pair = Some(pair.clone());
 9754                                break;
 9755                            }
 9756                        }
 9757                    }
 9758
 9759                    if let Some(pair) = bracket_pair {
 9760                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9761                        let autoclose_enabled =
 9762                            self.use_autoclose && snapshot_settings.use_autoclose;
 9763                        if autoclose_enabled {
 9764                            let start = snapshot.anchor_after(selection_head);
 9765                            let end = snapshot.anchor_after(selection_head);
 9766                            self.autoclose_regions.push(AutocloseRegion {
 9767                                selection_id: selection.id,
 9768                                range: start..end,
 9769                                pair,
 9770                            });
 9771                        }
 9772                    }
 9773                }
 9774            }
 9775        }
 9776        Ok(())
 9777    }
 9778
 9779    pub fn move_to_next_snippet_tabstop(
 9780        &mut self,
 9781        window: &mut Window,
 9782        cx: &mut Context<Self>,
 9783    ) -> bool {
 9784        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9785    }
 9786
 9787    pub fn move_to_prev_snippet_tabstop(
 9788        &mut self,
 9789        window: &mut Window,
 9790        cx: &mut Context<Self>,
 9791    ) -> bool {
 9792        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9793    }
 9794
 9795    pub fn move_to_snippet_tabstop(
 9796        &mut self,
 9797        bias: Bias,
 9798        window: &mut Window,
 9799        cx: &mut Context<Self>,
 9800    ) -> bool {
 9801        if let Some(mut snippet) = self.snippet_stack.pop() {
 9802            match bias {
 9803                Bias::Left => {
 9804                    if snippet.active_index > 0 {
 9805                        snippet.active_index -= 1;
 9806                    } else {
 9807                        self.snippet_stack.push(snippet);
 9808                        return false;
 9809                    }
 9810                }
 9811                Bias::Right => {
 9812                    if snippet.active_index + 1 < snippet.ranges.len() {
 9813                        snippet.active_index += 1;
 9814                    } else {
 9815                        self.snippet_stack.push(snippet);
 9816                        return false;
 9817                    }
 9818                }
 9819            }
 9820            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9821                self.change_selections(Default::default(), window, cx, |s| {
 9822                    // Reverse order so that the first range is the newest created selection.
 9823                    // Completions will use it and autoscroll will prioritize it.
 9824                    s.select_ranges(current_ranges.iter().rev().cloned())
 9825                });
 9826
 9827                if let Some(choices) = &snippet.choices[snippet.active_index]
 9828                    && let Some(selection) = current_ranges.first()
 9829                {
 9830                    self.show_snippet_choices(choices, selection.clone(), cx);
 9831                }
 9832
 9833                // If snippet state is not at the last tabstop, push it back on the stack
 9834                if snippet.active_index + 1 < snippet.ranges.len() {
 9835                    self.snippet_stack.push(snippet);
 9836                }
 9837                return true;
 9838            }
 9839        }
 9840
 9841        false
 9842    }
 9843
 9844    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9845        self.transact(window, cx, |this, window, cx| {
 9846            this.select_all(&SelectAll, window, cx);
 9847            this.insert("", window, cx);
 9848        });
 9849    }
 9850
 9851    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9852        if self.read_only(cx) {
 9853            return;
 9854        }
 9855        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9856        self.transact(window, cx, |this, window, cx| {
 9857            this.select_autoclose_pair(window, cx);
 9858
 9859            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9860
 9861            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9862            if !this.linked_edit_ranges.is_empty() {
 9863                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9864                let snapshot = this.buffer.read(cx).snapshot(cx);
 9865
 9866                for selection in selections.iter() {
 9867                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9868                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9869                    if selection_start.buffer_id != selection_end.buffer_id {
 9870                        continue;
 9871                    }
 9872                    if let Some(ranges) =
 9873                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9874                    {
 9875                        for (buffer, entries) in ranges {
 9876                            linked_ranges.entry(buffer).or_default().extend(entries);
 9877                        }
 9878                    }
 9879                }
 9880            }
 9881
 9882            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9883            for selection in &mut selections {
 9884                if selection.is_empty() {
 9885                    let old_head = selection.head();
 9886                    let mut new_head =
 9887                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9888                            .to_point(&display_map);
 9889                    if let Some((buffer, line_buffer_range)) = display_map
 9890                        .buffer_snapshot()
 9891                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9892                    {
 9893                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9894                        let indent_len = match indent_size.kind {
 9895                            IndentKind::Space => {
 9896                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9897                            }
 9898                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9899                        };
 9900                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9901                            let indent_len = indent_len.get();
 9902                            new_head = cmp::min(
 9903                                new_head,
 9904                                MultiBufferPoint::new(
 9905                                    old_head.row,
 9906                                    ((old_head.column - 1) / indent_len) * indent_len,
 9907                                ),
 9908                            );
 9909                        }
 9910                    }
 9911
 9912                    selection.set_head(new_head, SelectionGoal::None);
 9913                }
 9914            }
 9915
 9916            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9917            this.insert("", window, cx);
 9918            let empty_str: Arc<str> = Arc::from("");
 9919            for (buffer, edits) in linked_ranges {
 9920                let snapshot = buffer.read(cx).snapshot();
 9921                use text::ToPoint as TP;
 9922
 9923                let edits = edits
 9924                    .into_iter()
 9925                    .map(|range| {
 9926                        let end_point = TP::to_point(&range.end, &snapshot);
 9927                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9928
 9929                        if end_point == start_point {
 9930                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9931                                .saturating_sub(1);
 9932                            start_point =
 9933                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9934                        };
 9935
 9936                        (start_point..end_point, empty_str.clone())
 9937                    })
 9938                    .sorted_by_key(|(range, _)| range.start)
 9939                    .collect::<Vec<_>>();
 9940                buffer.update(cx, |this, cx| {
 9941                    this.edit(edits, None, cx);
 9942                })
 9943            }
 9944            this.refresh_edit_prediction(true, false, window, cx);
 9945            refresh_linked_ranges(this, window, cx);
 9946        });
 9947    }
 9948
 9949    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9950        if self.read_only(cx) {
 9951            return;
 9952        }
 9953        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9954        self.transact(window, cx, |this, window, cx| {
 9955            this.change_selections(Default::default(), window, cx, |s| {
 9956                s.move_with(|map, selection| {
 9957                    if selection.is_empty() {
 9958                        let cursor = movement::right(map, selection.head());
 9959                        selection.end = cursor;
 9960                        selection.reversed = true;
 9961                        selection.goal = SelectionGoal::None;
 9962                    }
 9963                })
 9964            });
 9965            this.insert("", window, cx);
 9966            this.refresh_edit_prediction(true, false, window, cx);
 9967        });
 9968    }
 9969
 9970    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9971        if self.mode.is_single_line() {
 9972            cx.propagate();
 9973            return;
 9974        }
 9975
 9976        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9977        if self.move_to_prev_snippet_tabstop(window, cx) {
 9978            return;
 9979        }
 9980        self.outdent(&Outdent, window, cx);
 9981    }
 9982
 9983    pub fn next_snippet_tabstop(
 9984        &mut self,
 9985        _: &NextSnippetTabstop,
 9986        window: &mut Window,
 9987        cx: &mut Context<Self>,
 9988    ) {
 9989        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
 9990            return;
 9991        }
 9992
 9993        if self.move_to_next_snippet_tabstop(window, cx) {
 9994            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9995            return;
 9996        }
 9997    }
 9998
 9999    pub fn previous_snippet_tabstop(
10000        &mut self,
10001        _: &PreviousSnippetTabstop,
10002        window: &mut Window,
10003        cx: &mut Context<Self>,
10004    ) {
10005        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10006            return;
10007        }
10008
10009        if self.move_to_prev_snippet_tabstop(window, cx) {
10010            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10011            return;
10012        }
10013    }
10014
10015    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10016        if self.mode.is_single_line() {
10017            cx.propagate();
10018            return;
10019        }
10020
10021        if self.move_to_next_snippet_tabstop(window, cx) {
10022            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10023            return;
10024        }
10025        if self.read_only(cx) {
10026            return;
10027        }
10028        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10029        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10030        let buffer = self.buffer.read(cx);
10031        let snapshot = buffer.snapshot(cx);
10032        let rows_iter = selections.iter().map(|s| s.head().row);
10033        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10034
10035        let has_some_cursor_in_whitespace = selections
10036            .iter()
10037            .filter(|selection| selection.is_empty())
10038            .any(|selection| {
10039                let cursor = selection.head();
10040                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10041                cursor.column < current_indent.len
10042            });
10043
10044        let mut edits = Vec::new();
10045        let mut prev_edited_row = 0;
10046        let mut row_delta = 0;
10047        for selection in &mut selections {
10048            if selection.start.row != prev_edited_row {
10049                row_delta = 0;
10050            }
10051            prev_edited_row = selection.end.row;
10052
10053            // If the selection is non-empty, then increase the indentation of the selected lines.
10054            if !selection.is_empty() {
10055                row_delta =
10056                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10057                continue;
10058            }
10059
10060            let cursor = selection.head();
10061            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10062            if let Some(suggested_indent) =
10063                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10064            {
10065                // Don't do anything if already at suggested indent
10066                // and there is any other cursor which is not
10067                if has_some_cursor_in_whitespace
10068                    && cursor.column == current_indent.len
10069                    && current_indent.len == suggested_indent.len
10070                {
10071                    continue;
10072                }
10073
10074                // Adjust line and move cursor to suggested indent
10075                // if cursor is not at suggested indent
10076                if cursor.column < suggested_indent.len
10077                    && cursor.column <= current_indent.len
10078                    && current_indent.len <= suggested_indent.len
10079                {
10080                    selection.start = Point::new(cursor.row, suggested_indent.len);
10081                    selection.end = selection.start;
10082                    if row_delta == 0 {
10083                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10084                            cursor.row,
10085                            current_indent,
10086                            suggested_indent,
10087                        ));
10088                        row_delta = suggested_indent.len - current_indent.len;
10089                    }
10090                    continue;
10091                }
10092
10093                // If current indent is more than suggested indent
10094                // only move cursor to current indent and skip indent
10095                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10096                    selection.start = Point::new(cursor.row, current_indent.len);
10097                    selection.end = selection.start;
10098                    continue;
10099                }
10100            }
10101
10102            // Otherwise, insert a hard or soft tab.
10103            let settings = buffer.language_settings_at(cursor, cx);
10104            let tab_size = if settings.hard_tabs {
10105                IndentSize::tab()
10106            } else {
10107                let tab_size = settings.tab_size.get();
10108                let indent_remainder = snapshot
10109                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10110                    .flat_map(str::chars)
10111                    .fold(row_delta % tab_size, |counter: u32, c| {
10112                        if c == '\t' {
10113                            0
10114                        } else {
10115                            (counter + 1) % tab_size
10116                        }
10117                    });
10118
10119                let chars_to_next_tab_stop = tab_size - indent_remainder;
10120                IndentSize::spaces(chars_to_next_tab_stop)
10121            };
10122            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10123            selection.end = selection.start;
10124            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10125            row_delta += tab_size.len;
10126        }
10127
10128        self.transact(window, cx, |this, window, cx| {
10129            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10130            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10131            this.refresh_edit_prediction(true, false, window, cx);
10132        });
10133    }
10134
10135    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10136        if self.read_only(cx) {
10137            return;
10138        }
10139        if self.mode.is_single_line() {
10140            cx.propagate();
10141            return;
10142        }
10143
10144        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10145        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10146        let mut prev_edited_row = 0;
10147        let mut row_delta = 0;
10148        let mut edits = Vec::new();
10149        let buffer = self.buffer.read(cx);
10150        let snapshot = buffer.snapshot(cx);
10151        for selection in &mut selections {
10152            if selection.start.row != prev_edited_row {
10153                row_delta = 0;
10154            }
10155            prev_edited_row = selection.end.row;
10156
10157            row_delta =
10158                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10159        }
10160
10161        self.transact(window, cx, |this, window, cx| {
10162            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10163            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10164        });
10165    }
10166
10167    fn indent_selection(
10168        buffer: &MultiBuffer,
10169        snapshot: &MultiBufferSnapshot,
10170        selection: &mut Selection<Point>,
10171        edits: &mut Vec<(Range<Point>, String)>,
10172        delta_for_start_row: u32,
10173        cx: &App,
10174    ) -> u32 {
10175        let settings = buffer.language_settings_at(selection.start, cx);
10176        let tab_size = settings.tab_size.get();
10177        let indent_kind = if settings.hard_tabs {
10178            IndentKind::Tab
10179        } else {
10180            IndentKind::Space
10181        };
10182        let mut start_row = selection.start.row;
10183        let mut end_row = selection.end.row + 1;
10184
10185        // If a selection ends at the beginning of a line, don't indent
10186        // that last line.
10187        if selection.end.column == 0 && selection.end.row > selection.start.row {
10188            end_row -= 1;
10189        }
10190
10191        // Avoid re-indenting a row that has already been indented by a
10192        // previous selection, but still update this selection's column
10193        // to reflect that indentation.
10194        if delta_for_start_row > 0 {
10195            start_row += 1;
10196            selection.start.column += delta_for_start_row;
10197            if selection.end.row == selection.start.row {
10198                selection.end.column += delta_for_start_row;
10199            }
10200        }
10201
10202        let mut delta_for_end_row = 0;
10203        let has_multiple_rows = start_row + 1 != end_row;
10204        for row in start_row..end_row {
10205            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10206            let indent_delta = match (current_indent.kind, indent_kind) {
10207                (IndentKind::Space, IndentKind::Space) => {
10208                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10209                    IndentSize::spaces(columns_to_next_tab_stop)
10210                }
10211                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10212                (_, IndentKind::Tab) => IndentSize::tab(),
10213            };
10214
10215            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10216                0
10217            } else {
10218                selection.start.column
10219            };
10220            let row_start = Point::new(row, start);
10221            edits.push((
10222                row_start..row_start,
10223                indent_delta.chars().collect::<String>(),
10224            ));
10225
10226            // Update this selection's endpoints to reflect the indentation.
10227            if row == selection.start.row {
10228                selection.start.column += indent_delta.len;
10229            }
10230            if row == selection.end.row {
10231                selection.end.column += indent_delta.len;
10232                delta_for_end_row = indent_delta.len;
10233            }
10234        }
10235
10236        if selection.start.row == selection.end.row {
10237            delta_for_start_row + delta_for_end_row
10238        } else {
10239            delta_for_end_row
10240        }
10241    }
10242
10243    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10244        if self.read_only(cx) {
10245            return;
10246        }
10247        if self.mode.is_single_line() {
10248            cx.propagate();
10249            return;
10250        }
10251
10252        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10253        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10254        let selections = self.selections.all::<Point>(&display_map);
10255        let mut deletion_ranges = Vec::new();
10256        let mut last_outdent = None;
10257        {
10258            let buffer = self.buffer.read(cx);
10259            let snapshot = buffer.snapshot(cx);
10260            for selection in &selections {
10261                let settings = buffer.language_settings_at(selection.start, cx);
10262                let tab_size = settings.tab_size.get();
10263                let mut rows = selection.spanned_rows(false, &display_map);
10264
10265                // Avoid re-outdenting a row that has already been outdented by a
10266                // previous selection.
10267                if let Some(last_row) = last_outdent
10268                    && last_row == rows.start
10269                {
10270                    rows.start = rows.start.next_row();
10271                }
10272                let has_multiple_rows = rows.len() > 1;
10273                for row in rows.iter_rows() {
10274                    let indent_size = snapshot.indent_size_for_line(row);
10275                    if indent_size.len > 0 {
10276                        let deletion_len = match indent_size.kind {
10277                            IndentKind::Space => {
10278                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10279                                if columns_to_prev_tab_stop == 0 {
10280                                    tab_size
10281                                } else {
10282                                    columns_to_prev_tab_stop
10283                                }
10284                            }
10285                            IndentKind::Tab => 1,
10286                        };
10287                        let start = if has_multiple_rows
10288                            || deletion_len > selection.start.column
10289                            || indent_size.len < selection.start.column
10290                        {
10291                            0
10292                        } else {
10293                            selection.start.column - deletion_len
10294                        };
10295                        deletion_ranges.push(
10296                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10297                        );
10298                        last_outdent = Some(row);
10299                    }
10300                }
10301            }
10302        }
10303
10304        self.transact(window, cx, |this, window, cx| {
10305            this.buffer.update(cx, |buffer, cx| {
10306                let empty_str: Arc<str> = Arc::default();
10307                buffer.edit(
10308                    deletion_ranges
10309                        .into_iter()
10310                        .map(|range| (range, empty_str.clone())),
10311                    None,
10312                    cx,
10313                );
10314            });
10315            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10316            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10317        });
10318    }
10319
10320    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10321        if self.read_only(cx) {
10322            return;
10323        }
10324        if self.mode.is_single_line() {
10325            cx.propagate();
10326            return;
10327        }
10328
10329        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10330        let selections = self
10331            .selections
10332            .all::<usize>(&self.display_snapshot(cx))
10333            .into_iter()
10334            .map(|s| s.range());
10335
10336        self.transact(window, cx, |this, window, cx| {
10337            this.buffer.update(cx, |buffer, cx| {
10338                buffer.autoindent_ranges(selections, cx);
10339            });
10340            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10341            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10342        });
10343    }
10344
10345    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10346        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10347        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10348        let selections = self.selections.all::<Point>(&display_map);
10349
10350        let mut new_cursors = Vec::new();
10351        let mut edit_ranges = Vec::new();
10352        let mut selections = selections.iter().peekable();
10353        while let Some(selection) = selections.next() {
10354            let mut rows = selection.spanned_rows(false, &display_map);
10355
10356            // Accumulate contiguous regions of rows that we want to delete.
10357            while let Some(next_selection) = selections.peek() {
10358                let next_rows = next_selection.spanned_rows(false, &display_map);
10359                if next_rows.start <= rows.end {
10360                    rows.end = next_rows.end;
10361                    selections.next().unwrap();
10362                } else {
10363                    break;
10364                }
10365            }
10366
10367            let buffer = display_map.buffer_snapshot();
10368            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10369            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10370                // If there's a line after the range, delete the \n from the end of the row range
10371                (
10372                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10373                    rows.end,
10374                )
10375            } else {
10376                // If there isn't a line after the range, delete the \n from the line before the
10377                // start of the row range
10378                edit_start = edit_start.saturating_sub(1);
10379                (buffer.len(), rows.start.previous_row())
10380            };
10381
10382            let text_layout_details = self.text_layout_details(window);
10383            let x = display_map.x_for_display_point(
10384                selection.head().to_display_point(&display_map),
10385                &text_layout_details,
10386            );
10387            let row = Point::new(target_row.0, 0)
10388                .to_display_point(&display_map)
10389                .row();
10390            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10391
10392            new_cursors.push((
10393                selection.id,
10394                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10395                SelectionGoal::None,
10396            ));
10397            edit_ranges.push(edit_start..edit_end);
10398        }
10399
10400        self.transact(window, cx, |this, window, cx| {
10401            let buffer = this.buffer.update(cx, |buffer, cx| {
10402                let empty_str: Arc<str> = Arc::default();
10403                buffer.edit(
10404                    edit_ranges
10405                        .into_iter()
10406                        .map(|range| (range, empty_str.clone())),
10407                    None,
10408                    cx,
10409                );
10410                buffer.snapshot(cx)
10411            });
10412            let new_selections = new_cursors
10413                .into_iter()
10414                .map(|(id, cursor, goal)| {
10415                    let cursor = cursor.to_point(&buffer);
10416                    Selection {
10417                        id,
10418                        start: cursor,
10419                        end: cursor,
10420                        reversed: false,
10421                        goal,
10422                    }
10423                })
10424                .collect();
10425
10426            this.change_selections(Default::default(), window, cx, |s| {
10427                s.select(new_selections);
10428            });
10429        });
10430    }
10431
10432    pub fn join_lines_impl(
10433        &mut self,
10434        insert_whitespace: bool,
10435        window: &mut Window,
10436        cx: &mut Context<Self>,
10437    ) {
10438        if self.read_only(cx) {
10439            return;
10440        }
10441        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10442        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10443            let start = MultiBufferRow(selection.start.row);
10444            // Treat single line selections as if they include the next line. Otherwise this action
10445            // would do nothing for single line selections individual cursors.
10446            let end = if selection.start.row == selection.end.row {
10447                MultiBufferRow(selection.start.row + 1)
10448            } else {
10449                MultiBufferRow(selection.end.row)
10450            };
10451
10452            if let Some(last_row_range) = row_ranges.last_mut()
10453                && start <= last_row_range.end
10454            {
10455                last_row_range.end = end;
10456                continue;
10457            }
10458            row_ranges.push(start..end);
10459        }
10460
10461        let snapshot = self.buffer.read(cx).snapshot(cx);
10462        let mut cursor_positions = Vec::new();
10463        for row_range in &row_ranges {
10464            let anchor = snapshot.anchor_before(Point::new(
10465                row_range.end.previous_row().0,
10466                snapshot.line_len(row_range.end.previous_row()),
10467            ));
10468            cursor_positions.push(anchor..anchor);
10469        }
10470
10471        self.transact(window, cx, |this, window, cx| {
10472            for row_range in row_ranges.into_iter().rev() {
10473                for row in row_range.iter_rows().rev() {
10474                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10475                    let next_line_row = row.next_row();
10476                    let indent = snapshot.indent_size_for_line(next_line_row);
10477                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10478
10479                    let replace =
10480                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10481                            " "
10482                        } else {
10483                            ""
10484                        };
10485
10486                    this.buffer.update(cx, |buffer, cx| {
10487                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10488                    });
10489                }
10490            }
10491
10492            this.change_selections(Default::default(), window, cx, |s| {
10493                s.select_anchor_ranges(cursor_positions)
10494            });
10495        });
10496    }
10497
10498    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10499        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10500        self.join_lines_impl(true, window, cx);
10501    }
10502
10503    pub fn sort_lines_case_sensitive(
10504        &mut self,
10505        _: &SortLinesCaseSensitive,
10506        window: &mut Window,
10507        cx: &mut Context<Self>,
10508    ) {
10509        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10510    }
10511
10512    pub fn sort_lines_by_length(
10513        &mut self,
10514        _: &SortLinesByLength,
10515        window: &mut Window,
10516        cx: &mut Context<Self>,
10517    ) {
10518        self.manipulate_immutable_lines(window, cx, |lines| {
10519            lines.sort_by_key(|&line| line.chars().count())
10520        })
10521    }
10522
10523    pub fn sort_lines_case_insensitive(
10524        &mut self,
10525        _: &SortLinesCaseInsensitive,
10526        window: &mut Window,
10527        cx: &mut Context<Self>,
10528    ) {
10529        self.manipulate_immutable_lines(window, cx, |lines| {
10530            lines.sort_by_key(|line| line.to_lowercase())
10531        })
10532    }
10533
10534    pub fn unique_lines_case_insensitive(
10535        &mut self,
10536        _: &UniqueLinesCaseInsensitive,
10537        window: &mut Window,
10538        cx: &mut Context<Self>,
10539    ) {
10540        self.manipulate_immutable_lines(window, cx, |lines| {
10541            let mut seen = HashSet::default();
10542            lines.retain(|line| seen.insert(line.to_lowercase()));
10543        })
10544    }
10545
10546    pub fn unique_lines_case_sensitive(
10547        &mut self,
10548        _: &UniqueLinesCaseSensitive,
10549        window: &mut Window,
10550        cx: &mut Context<Self>,
10551    ) {
10552        self.manipulate_immutable_lines(window, cx, |lines| {
10553            let mut seen = HashSet::default();
10554            lines.retain(|line| seen.insert(*line));
10555        })
10556    }
10557
10558    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10559        let snapshot = self.buffer.read(cx).snapshot(cx);
10560        for selection in self.selections.disjoint_anchors_arc().iter() {
10561            if snapshot
10562                .language_at(selection.start)
10563                .and_then(|lang| lang.config().wrap_characters.as_ref())
10564                .is_some()
10565            {
10566                return true;
10567            }
10568        }
10569        false
10570    }
10571
10572    fn wrap_selections_in_tag(
10573        &mut self,
10574        _: &WrapSelectionsInTag,
10575        window: &mut Window,
10576        cx: &mut Context<Self>,
10577    ) {
10578        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10579
10580        let snapshot = self.buffer.read(cx).snapshot(cx);
10581
10582        let mut edits = Vec::new();
10583        let mut boundaries = Vec::new();
10584
10585        for selection in self
10586            .selections
10587            .all_adjusted(&self.display_snapshot(cx))
10588            .iter()
10589        {
10590            let Some(wrap_config) = snapshot
10591                .language_at(selection.start)
10592                .and_then(|lang| lang.config().wrap_characters.clone())
10593            else {
10594                continue;
10595            };
10596
10597            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10598            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10599
10600            let start_before = snapshot.anchor_before(selection.start);
10601            let end_after = snapshot.anchor_after(selection.end);
10602
10603            edits.push((start_before..start_before, open_tag));
10604            edits.push((end_after..end_after, close_tag));
10605
10606            boundaries.push((
10607                start_before,
10608                end_after,
10609                wrap_config.start_prefix.len(),
10610                wrap_config.end_suffix.len(),
10611            ));
10612        }
10613
10614        if edits.is_empty() {
10615            return;
10616        }
10617
10618        self.transact(window, cx, |this, window, cx| {
10619            let buffer = this.buffer.update(cx, |buffer, cx| {
10620                buffer.edit(edits, None, cx);
10621                buffer.snapshot(cx)
10622            });
10623
10624            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10625            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10626                boundaries.into_iter()
10627            {
10628                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10629                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10630                new_selections.push(open_offset..open_offset);
10631                new_selections.push(close_offset..close_offset);
10632            }
10633
10634            this.change_selections(Default::default(), window, cx, |s| {
10635                s.select_ranges(new_selections);
10636            });
10637
10638            this.request_autoscroll(Autoscroll::fit(), cx);
10639        });
10640    }
10641
10642    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10643        let Some(project) = self.project.clone() else {
10644            return;
10645        };
10646        self.reload(project, window, cx)
10647            .detach_and_notify_err(window, cx);
10648    }
10649
10650    pub fn restore_file(
10651        &mut self,
10652        _: &::git::RestoreFile,
10653        window: &mut Window,
10654        cx: &mut Context<Self>,
10655    ) {
10656        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10657        let mut buffer_ids = HashSet::default();
10658        let snapshot = self.buffer().read(cx).snapshot(cx);
10659        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10660            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10661        }
10662
10663        let buffer = self.buffer().read(cx);
10664        let ranges = buffer_ids
10665            .into_iter()
10666            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10667            .collect::<Vec<_>>();
10668
10669        self.restore_hunks_in_ranges(ranges, window, cx);
10670    }
10671
10672    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10673        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10674        let selections = self
10675            .selections
10676            .all(&self.display_snapshot(cx))
10677            .into_iter()
10678            .map(|s| s.range())
10679            .collect();
10680        self.restore_hunks_in_ranges(selections, window, cx);
10681    }
10682
10683    pub fn restore_hunks_in_ranges(
10684        &mut self,
10685        ranges: Vec<Range<Point>>,
10686        window: &mut Window,
10687        cx: &mut Context<Editor>,
10688    ) {
10689        let mut revert_changes = HashMap::default();
10690        let chunk_by = self
10691            .snapshot(window, cx)
10692            .hunks_for_ranges(ranges)
10693            .into_iter()
10694            .chunk_by(|hunk| hunk.buffer_id);
10695        for (buffer_id, hunks) in &chunk_by {
10696            let hunks = hunks.collect::<Vec<_>>();
10697            for hunk in &hunks {
10698                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10699            }
10700            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10701        }
10702        drop(chunk_by);
10703        if !revert_changes.is_empty() {
10704            self.transact(window, cx, |editor, window, cx| {
10705                editor.restore(revert_changes, window, cx);
10706            });
10707        }
10708    }
10709
10710    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10711        if let Some(status) = self
10712            .addons
10713            .iter()
10714            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10715        {
10716            return Some(status);
10717        }
10718        self.project
10719            .as_ref()?
10720            .read(cx)
10721            .status_for_buffer_id(buffer_id, cx)
10722    }
10723
10724    pub fn open_active_item_in_terminal(
10725        &mut self,
10726        _: &OpenInTerminal,
10727        window: &mut Window,
10728        cx: &mut Context<Self>,
10729    ) {
10730        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10731            let project_path = buffer.read(cx).project_path(cx)?;
10732            let project = self.project()?.read(cx);
10733            let entry = project.entry_for_path(&project_path, cx)?;
10734            let parent = match &entry.canonical_path {
10735                Some(canonical_path) => canonical_path.to_path_buf(),
10736                None => project.absolute_path(&project_path, cx)?,
10737            }
10738            .parent()?
10739            .to_path_buf();
10740            Some(parent)
10741        }) {
10742            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10743        }
10744    }
10745
10746    fn set_breakpoint_context_menu(
10747        &mut self,
10748        display_row: DisplayRow,
10749        position: Option<Anchor>,
10750        clicked_point: gpui::Point<Pixels>,
10751        window: &mut Window,
10752        cx: &mut Context<Self>,
10753    ) {
10754        let source = self
10755            .buffer
10756            .read(cx)
10757            .snapshot(cx)
10758            .anchor_before(Point::new(display_row.0, 0u32));
10759
10760        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10761
10762        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10763            self,
10764            source,
10765            clicked_point,
10766            context_menu,
10767            window,
10768            cx,
10769        );
10770    }
10771
10772    fn add_edit_breakpoint_block(
10773        &mut self,
10774        anchor: Anchor,
10775        breakpoint: &Breakpoint,
10776        edit_action: BreakpointPromptEditAction,
10777        window: &mut Window,
10778        cx: &mut Context<Self>,
10779    ) {
10780        let weak_editor = cx.weak_entity();
10781        let bp_prompt = cx.new(|cx| {
10782            BreakpointPromptEditor::new(
10783                weak_editor,
10784                anchor,
10785                breakpoint.clone(),
10786                edit_action,
10787                window,
10788                cx,
10789            )
10790        });
10791
10792        let height = bp_prompt.update(cx, |this, cx| {
10793            this.prompt
10794                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10795        });
10796        let cloned_prompt = bp_prompt.clone();
10797        let blocks = vec![BlockProperties {
10798            style: BlockStyle::Sticky,
10799            placement: BlockPlacement::Above(anchor),
10800            height: Some(height),
10801            render: Arc::new(move |cx| {
10802                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10803                cloned_prompt.clone().into_any_element()
10804            }),
10805            priority: 0,
10806        }];
10807
10808        let focus_handle = bp_prompt.focus_handle(cx);
10809        window.focus(&focus_handle);
10810
10811        let block_ids = self.insert_blocks(blocks, None, cx);
10812        bp_prompt.update(cx, |prompt, _| {
10813            prompt.add_block_ids(block_ids);
10814        });
10815    }
10816
10817    pub(crate) fn breakpoint_at_row(
10818        &self,
10819        row: u32,
10820        window: &mut Window,
10821        cx: &mut Context<Self>,
10822    ) -> Option<(Anchor, Breakpoint)> {
10823        let snapshot = self.snapshot(window, cx);
10824        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10825
10826        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10827    }
10828
10829    pub(crate) fn breakpoint_at_anchor(
10830        &self,
10831        breakpoint_position: Anchor,
10832        snapshot: &EditorSnapshot,
10833        cx: &mut Context<Self>,
10834    ) -> Option<(Anchor, Breakpoint)> {
10835        let buffer = self
10836            .buffer
10837            .read(cx)
10838            .buffer_for_anchor(breakpoint_position, cx)?;
10839
10840        let enclosing_excerpt = breakpoint_position.excerpt_id;
10841        let buffer_snapshot = buffer.read(cx).snapshot();
10842
10843        let row = buffer_snapshot
10844            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10845            .row;
10846
10847        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10848        let anchor_end = snapshot
10849            .buffer_snapshot()
10850            .anchor_after(Point::new(row, line_len));
10851
10852        self.breakpoint_store
10853            .as_ref()?
10854            .read_with(cx, |breakpoint_store, cx| {
10855                breakpoint_store
10856                    .breakpoints(
10857                        &buffer,
10858                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10859                        &buffer_snapshot,
10860                        cx,
10861                    )
10862                    .next()
10863                    .and_then(|(bp, _)| {
10864                        let breakpoint_row = buffer_snapshot
10865                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10866                            .row;
10867
10868                        if breakpoint_row == row {
10869                            snapshot
10870                                .buffer_snapshot()
10871                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10872                                .map(|position| (position, bp.bp.clone()))
10873                        } else {
10874                            None
10875                        }
10876                    })
10877            })
10878    }
10879
10880    pub fn edit_log_breakpoint(
10881        &mut self,
10882        _: &EditLogBreakpoint,
10883        window: &mut Window,
10884        cx: &mut Context<Self>,
10885    ) {
10886        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10887            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10888                message: None,
10889                state: BreakpointState::Enabled,
10890                condition: None,
10891                hit_condition: None,
10892            });
10893
10894            self.add_edit_breakpoint_block(
10895                anchor,
10896                &breakpoint,
10897                BreakpointPromptEditAction::Log,
10898                window,
10899                cx,
10900            );
10901        }
10902    }
10903
10904    fn breakpoints_at_cursors(
10905        &self,
10906        window: &mut Window,
10907        cx: &mut Context<Self>,
10908    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10909        let snapshot = self.snapshot(window, cx);
10910        let cursors = self
10911            .selections
10912            .disjoint_anchors_arc()
10913            .iter()
10914            .map(|selection| {
10915                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
10916
10917                let breakpoint_position = self
10918                    .breakpoint_at_row(cursor_position.row, window, cx)
10919                    .map(|bp| bp.0)
10920                    .unwrap_or_else(|| {
10921                        snapshot
10922                            .display_snapshot
10923                            .buffer_snapshot()
10924                            .anchor_after(Point::new(cursor_position.row, 0))
10925                    });
10926
10927                let breakpoint = self
10928                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10929                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10930
10931                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10932            })
10933            // 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.
10934            .collect::<HashMap<Anchor, _>>();
10935
10936        cursors.into_iter().collect()
10937    }
10938
10939    pub fn enable_breakpoint(
10940        &mut self,
10941        _: &crate::actions::EnableBreakpoint,
10942        window: &mut Window,
10943        cx: &mut Context<Self>,
10944    ) {
10945        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10946            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10947                continue;
10948            };
10949            self.edit_breakpoint_at_anchor(
10950                anchor,
10951                breakpoint,
10952                BreakpointEditAction::InvertState,
10953                cx,
10954            );
10955        }
10956    }
10957
10958    pub fn disable_breakpoint(
10959        &mut self,
10960        _: &crate::actions::DisableBreakpoint,
10961        window: &mut Window,
10962        cx: &mut Context<Self>,
10963    ) {
10964        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10965            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10966                continue;
10967            };
10968            self.edit_breakpoint_at_anchor(
10969                anchor,
10970                breakpoint,
10971                BreakpointEditAction::InvertState,
10972                cx,
10973            );
10974        }
10975    }
10976
10977    pub fn toggle_breakpoint(
10978        &mut self,
10979        _: &crate::actions::ToggleBreakpoint,
10980        window: &mut Window,
10981        cx: &mut Context<Self>,
10982    ) {
10983        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10984            if let Some(breakpoint) = breakpoint {
10985                self.edit_breakpoint_at_anchor(
10986                    anchor,
10987                    breakpoint,
10988                    BreakpointEditAction::Toggle,
10989                    cx,
10990                );
10991            } else {
10992                self.edit_breakpoint_at_anchor(
10993                    anchor,
10994                    Breakpoint::new_standard(),
10995                    BreakpointEditAction::Toggle,
10996                    cx,
10997                );
10998            }
10999        }
11000    }
11001
11002    pub fn edit_breakpoint_at_anchor(
11003        &mut self,
11004        breakpoint_position: Anchor,
11005        breakpoint: Breakpoint,
11006        edit_action: BreakpointEditAction,
11007        cx: &mut Context<Self>,
11008    ) {
11009        let Some(breakpoint_store) = &self.breakpoint_store else {
11010            return;
11011        };
11012
11013        let Some(buffer) = self
11014            .buffer
11015            .read(cx)
11016            .buffer_for_anchor(breakpoint_position, cx)
11017        else {
11018            return;
11019        };
11020
11021        breakpoint_store.update(cx, |breakpoint_store, cx| {
11022            breakpoint_store.toggle_breakpoint(
11023                buffer,
11024                BreakpointWithPosition {
11025                    position: breakpoint_position.text_anchor,
11026                    bp: breakpoint,
11027                },
11028                edit_action,
11029                cx,
11030            );
11031        });
11032
11033        cx.notify();
11034    }
11035
11036    #[cfg(any(test, feature = "test-support"))]
11037    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11038        self.breakpoint_store.clone()
11039    }
11040
11041    pub fn prepare_restore_change(
11042        &self,
11043        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11044        hunk: &MultiBufferDiffHunk,
11045        cx: &mut App,
11046    ) -> Option<()> {
11047        if hunk.is_created_file() {
11048            return None;
11049        }
11050        let buffer = self.buffer.read(cx);
11051        let diff = buffer.diff_for(hunk.buffer_id)?;
11052        let buffer = buffer.buffer(hunk.buffer_id)?;
11053        let buffer = buffer.read(cx);
11054        let original_text = diff
11055            .read(cx)
11056            .base_text()
11057            .as_rope()
11058            .slice(hunk.diff_base_byte_range.clone());
11059        let buffer_snapshot = buffer.snapshot();
11060        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11061        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11062            probe
11063                .0
11064                .start
11065                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11066                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11067        }) {
11068            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11069            Some(())
11070        } else {
11071            None
11072        }
11073    }
11074
11075    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11076        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11077    }
11078
11079    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11080        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11081    }
11082
11083    fn manipulate_lines<M>(
11084        &mut self,
11085        window: &mut Window,
11086        cx: &mut Context<Self>,
11087        mut manipulate: M,
11088    ) where
11089        M: FnMut(&str) -> LineManipulationResult,
11090    {
11091        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11092
11093        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11094        let buffer = self.buffer.read(cx).snapshot(cx);
11095
11096        let mut edits = Vec::new();
11097
11098        let selections = self.selections.all::<Point>(&display_map);
11099        let mut selections = selections.iter().peekable();
11100        let mut contiguous_row_selections = Vec::new();
11101        let mut new_selections = Vec::new();
11102        let mut added_lines = 0;
11103        let mut removed_lines = 0;
11104
11105        while let Some(selection) = selections.next() {
11106            let (start_row, end_row) = consume_contiguous_rows(
11107                &mut contiguous_row_selections,
11108                selection,
11109                &display_map,
11110                &mut selections,
11111            );
11112
11113            let start_point = Point::new(start_row.0, 0);
11114            let end_point = Point::new(
11115                end_row.previous_row().0,
11116                buffer.line_len(end_row.previous_row()),
11117            );
11118            let text = buffer
11119                .text_for_range(start_point..end_point)
11120                .collect::<String>();
11121
11122            let LineManipulationResult {
11123                new_text,
11124                line_count_before,
11125                line_count_after,
11126            } = manipulate(&text);
11127
11128            edits.push((start_point..end_point, new_text));
11129
11130            // Selections must change based on added and removed line count
11131            let start_row =
11132                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11133            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11134            new_selections.push(Selection {
11135                id: selection.id,
11136                start: start_row,
11137                end: end_row,
11138                goal: SelectionGoal::None,
11139                reversed: selection.reversed,
11140            });
11141
11142            if line_count_after > line_count_before {
11143                added_lines += line_count_after - line_count_before;
11144            } else if line_count_before > line_count_after {
11145                removed_lines += line_count_before - line_count_after;
11146            }
11147        }
11148
11149        self.transact(window, cx, |this, window, cx| {
11150            let buffer = this.buffer.update(cx, |buffer, cx| {
11151                buffer.edit(edits, None, cx);
11152                buffer.snapshot(cx)
11153            });
11154
11155            // Recalculate offsets on newly edited buffer
11156            let new_selections = new_selections
11157                .iter()
11158                .map(|s| {
11159                    let start_point = Point::new(s.start.0, 0);
11160                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11161                    Selection {
11162                        id: s.id,
11163                        start: buffer.point_to_offset(start_point),
11164                        end: buffer.point_to_offset(end_point),
11165                        goal: s.goal,
11166                        reversed: s.reversed,
11167                    }
11168                })
11169                .collect();
11170
11171            this.change_selections(Default::default(), window, cx, |s| {
11172                s.select(new_selections);
11173            });
11174
11175            this.request_autoscroll(Autoscroll::fit(), cx);
11176        });
11177    }
11178
11179    fn manipulate_immutable_lines<Fn>(
11180        &mut self,
11181        window: &mut Window,
11182        cx: &mut Context<Self>,
11183        mut callback: Fn,
11184    ) where
11185        Fn: FnMut(&mut Vec<&str>),
11186    {
11187        self.manipulate_lines(window, cx, |text| {
11188            let mut lines: Vec<&str> = text.split('\n').collect();
11189            let line_count_before = lines.len();
11190
11191            callback(&mut lines);
11192
11193            LineManipulationResult {
11194                new_text: lines.join("\n"),
11195                line_count_before,
11196                line_count_after: lines.len(),
11197            }
11198        });
11199    }
11200
11201    fn manipulate_mutable_lines<Fn>(
11202        &mut self,
11203        window: &mut Window,
11204        cx: &mut Context<Self>,
11205        mut callback: Fn,
11206    ) where
11207        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11208    {
11209        self.manipulate_lines(window, cx, |text| {
11210            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11211            let line_count_before = lines.len();
11212
11213            callback(&mut lines);
11214
11215            LineManipulationResult {
11216                new_text: lines.join("\n"),
11217                line_count_before,
11218                line_count_after: lines.len(),
11219            }
11220        });
11221    }
11222
11223    pub fn convert_indentation_to_spaces(
11224        &mut self,
11225        _: &ConvertIndentationToSpaces,
11226        window: &mut Window,
11227        cx: &mut Context<Self>,
11228    ) {
11229        let settings = self.buffer.read(cx).language_settings(cx);
11230        let tab_size = settings.tab_size.get() as usize;
11231
11232        self.manipulate_mutable_lines(window, cx, |lines| {
11233            // Allocates a reasonably sized scratch buffer once for the whole loop
11234            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11235            // Avoids recomputing spaces that could be inserted many times
11236            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11237                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11238                .collect();
11239
11240            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11241                let mut chars = line.as_ref().chars();
11242                let mut col = 0;
11243                let mut changed = false;
11244
11245                for ch in chars.by_ref() {
11246                    match ch {
11247                        ' ' => {
11248                            reindented_line.push(' ');
11249                            col += 1;
11250                        }
11251                        '\t' => {
11252                            // \t are converted to spaces depending on the current column
11253                            let spaces_len = tab_size - (col % tab_size);
11254                            reindented_line.extend(&space_cache[spaces_len - 1]);
11255                            col += spaces_len;
11256                            changed = true;
11257                        }
11258                        _ => {
11259                            // If we dont append before break, the character is consumed
11260                            reindented_line.push(ch);
11261                            break;
11262                        }
11263                    }
11264                }
11265
11266                if !changed {
11267                    reindented_line.clear();
11268                    continue;
11269                }
11270                // Append the rest of the line and replace old reference with new one
11271                reindented_line.extend(chars);
11272                *line = Cow::Owned(reindented_line.clone());
11273                reindented_line.clear();
11274            }
11275        });
11276    }
11277
11278    pub fn convert_indentation_to_tabs(
11279        &mut self,
11280        _: &ConvertIndentationToTabs,
11281        window: &mut Window,
11282        cx: &mut Context<Self>,
11283    ) {
11284        let settings = self.buffer.read(cx).language_settings(cx);
11285        let tab_size = settings.tab_size.get() as usize;
11286
11287        self.manipulate_mutable_lines(window, cx, |lines| {
11288            // Allocates a reasonably sized buffer once for the whole loop
11289            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11290            // Avoids recomputing spaces that could be inserted many times
11291            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11292                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11293                .collect();
11294
11295            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11296                let mut chars = line.chars();
11297                let mut spaces_count = 0;
11298                let mut first_non_indent_char = None;
11299                let mut changed = false;
11300
11301                for ch in chars.by_ref() {
11302                    match ch {
11303                        ' ' => {
11304                            // Keep track of spaces. Append \t when we reach tab_size
11305                            spaces_count += 1;
11306                            changed = true;
11307                            if spaces_count == tab_size {
11308                                reindented_line.push('\t');
11309                                spaces_count = 0;
11310                            }
11311                        }
11312                        '\t' => {
11313                            reindented_line.push('\t');
11314                            spaces_count = 0;
11315                        }
11316                        _ => {
11317                            // Dont append it yet, we might have remaining spaces
11318                            first_non_indent_char = Some(ch);
11319                            break;
11320                        }
11321                    }
11322                }
11323
11324                if !changed {
11325                    reindented_line.clear();
11326                    continue;
11327                }
11328                // Remaining spaces that didn't make a full tab stop
11329                if spaces_count > 0 {
11330                    reindented_line.extend(&space_cache[spaces_count - 1]);
11331                }
11332                // If we consume an extra character that was not indentation, add it back
11333                if let Some(extra_char) = first_non_indent_char {
11334                    reindented_line.push(extra_char);
11335                }
11336                // Append the rest of the line and replace old reference with new one
11337                reindented_line.extend(chars);
11338                *line = Cow::Owned(reindented_line.clone());
11339                reindented_line.clear();
11340            }
11341        });
11342    }
11343
11344    pub fn convert_to_upper_case(
11345        &mut self,
11346        _: &ConvertToUpperCase,
11347        window: &mut Window,
11348        cx: &mut Context<Self>,
11349    ) {
11350        self.manipulate_text(window, cx, |text| text.to_uppercase())
11351    }
11352
11353    pub fn convert_to_lower_case(
11354        &mut self,
11355        _: &ConvertToLowerCase,
11356        window: &mut Window,
11357        cx: &mut Context<Self>,
11358    ) {
11359        self.manipulate_text(window, cx, |text| text.to_lowercase())
11360    }
11361
11362    pub fn convert_to_title_case(
11363        &mut self,
11364        _: &ConvertToTitleCase,
11365        window: &mut Window,
11366        cx: &mut Context<Self>,
11367    ) {
11368        self.manipulate_text(window, cx, |text| {
11369            text.split('\n')
11370                .map(|line| line.to_case(Case::Title))
11371                .join("\n")
11372        })
11373    }
11374
11375    pub fn convert_to_snake_case(
11376        &mut self,
11377        _: &ConvertToSnakeCase,
11378        window: &mut Window,
11379        cx: &mut Context<Self>,
11380    ) {
11381        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11382    }
11383
11384    pub fn convert_to_kebab_case(
11385        &mut self,
11386        _: &ConvertToKebabCase,
11387        window: &mut Window,
11388        cx: &mut Context<Self>,
11389    ) {
11390        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11391    }
11392
11393    pub fn convert_to_upper_camel_case(
11394        &mut self,
11395        _: &ConvertToUpperCamelCase,
11396        window: &mut Window,
11397        cx: &mut Context<Self>,
11398    ) {
11399        self.manipulate_text(window, cx, |text| {
11400            text.split('\n')
11401                .map(|line| line.to_case(Case::UpperCamel))
11402                .join("\n")
11403        })
11404    }
11405
11406    pub fn convert_to_lower_camel_case(
11407        &mut self,
11408        _: &ConvertToLowerCamelCase,
11409        window: &mut Window,
11410        cx: &mut Context<Self>,
11411    ) {
11412        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11413    }
11414
11415    pub fn convert_to_opposite_case(
11416        &mut self,
11417        _: &ConvertToOppositeCase,
11418        window: &mut Window,
11419        cx: &mut Context<Self>,
11420    ) {
11421        self.manipulate_text(window, cx, |text| {
11422            text.chars()
11423                .fold(String::with_capacity(text.len()), |mut t, c| {
11424                    if c.is_uppercase() {
11425                        t.extend(c.to_lowercase());
11426                    } else {
11427                        t.extend(c.to_uppercase());
11428                    }
11429                    t
11430                })
11431        })
11432    }
11433
11434    pub fn convert_to_sentence_case(
11435        &mut self,
11436        _: &ConvertToSentenceCase,
11437        window: &mut Window,
11438        cx: &mut Context<Self>,
11439    ) {
11440        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11441    }
11442
11443    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11444        self.manipulate_text(window, cx, |text| {
11445            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11446            if has_upper_case_characters {
11447                text.to_lowercase()
11448            } else {
11449                text.to_uppercase()
11450            }
11451        })
11452    }
11453
11454    pub fn convert_to_rot13(
11455        &mut self,
11456        _: &ConvertToRot13,
11457        window: &mut Window,
11458        cx: &mut Context<Self>,
11459    ) {
11460        self.manipulate_text(window, cx, |text| {
11461            text.chars()
11462                .map(|c| match c {
11463                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11464                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11465                    _ => c,
11466                })
11467                .collect()
11468        })
11469    }
11470
11471    pub fn convert_to_rot47(
11472        &mut self,
11473        _: &ConvertToRot47,
11474        window: &mut Window,
11475        cx: &mut Context<Self>,
11476    ) {
11477        self.manipulate_text(window, cx, |text| {
11478            text.chars()
11479                .map(|c| {
11480                    let code_point = c as u32;
11481                    if code_point >= 33 && code_point <= 126 {
11482                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11483                    }
11484                    c
11485                })
11486                .collect()
11487        })
11488    }
11489
11490    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11491    where
11492        Fn: FnMut(&str) -> String,
11493    {
11494        let buffer = self.buffer.read(cx).snapshot(cx);
11495
11496        let mut new_selections = Vec::new();
11497        let mut edits = Vec::new();
11498        let mut selection_adjustment = 0i32;
11499
11500        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11501            let selection_is_empty = selection.is_empty();
11502
11503            let (start, end) = if selection_is_empty {
11504                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11505                (word_range.start, word_range.end)
11506            } else {
11507                (
11508                    buffer.point_to_offset(selection.start),
11509                    buffer.point_to_offset(selection.end),
11510                )
11511            };
11512
11513            let text = buffer.text_for_range(start..end).collect::<String>();
11514            let old_length = text.len() as i32;
11515            let text = callback(&text);
11516
11517            new_selections.push(Selection {
11518                start: (start as i32 - selection_adjustment) as usize,
11519                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11520                goal: SelectionGoal::None,
11521                id: selection.id,
11522                reversed: selection.reversed,
11523            });
11524
11525            selection_adjustment += old_length - text.len() as i32;
11526
11527            edits.push((start..end, text));
11528        }
11529
11530        self.transact(window, cx, |this, window, cx| {
11531            this.buffer.update(cx, |buffer, cx| {
11532                buffer.edit(edits, None, cx);
11533            });
11534
11535            this.change_selections(Default::default(), window, cx, |s| {
11536                s.select(new_selections);
11537            });
11538
11539            this.request_autoscroll(Autoscroll::fit(), cx);
11540        });
11541    }
11542
11543    pub fn move_selection_on_drop(
11544        &mut self,
11545        selection: &Selection<Anchor>,
11546        target: DisplayPoint,
11547        is_cut: bool,
11548        window: &mut Window,
11549        cx: &mut Context<Self>,
11550    ) {
11551        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11552        let buffer = display_map.buffer_snapshot();
11553        let mut edits = Vec::new();
11554        let insert_point = display_map
11555            .clip_point(target, Bias::Left)
11556            .to_point(&display_map);
11557        let text = buffer
11558            .text_for_range(selection.start..selection.end)
11559            .collect::<String>();
11560        if is_cut {
11561            edits.push(((selection.start..selection.end), String::new()));
11562        }
11563        let insert_anchor = buffer.anchor_before(insert_point);
11564        edits.push(((insert_anchor..insert_anchor), text));
11565        let last_edit_start = insert_anchor.bias_left(buffer);
11566        let last_edit_end = insert_anchor.bias_right(buffer);
11567        self.transact(window, cx, |this, window, cx| {
11568            this.buffer.update(cx, |buffer, cx| {
11569                buffer.edit(edits, None, cx);
11570            });
11571            this.change_selections(Default::default(), window, cx, |s| {
11572                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11573            });
11574        });
11575    }
11576
11577    pub fn clear_selection_drag_state(&mut self) {
11578        self.selection_drag_state = SelectionDragState::None;
11579    }
11580
11581    pub fn duplicate(
11582        &mut self,
11583        upwards: bool,
11584        whole_lines: bool,
11585        window: &mut Window,
11586        cx: &mut Context<Self>,
11587    ) {
11588        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11589
11590        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11591        let buffer = display_map.buffer_snapshot();
11592        let selections = self.selections.all::<Point>(&display_map);
11593
11594        let mut edits = Vec::new();
11595        let mut selections_iter = selections.iter().peekable();
11596        while let Some(selection) = selections_iter.next() {
11597            let mut rows = selection.spanned_rows(false, &display_map);
11598            // duplicate line-wise
11599            if whole_lines || selection.start == selection.end {
11600                // Avoid duplicating the same lines twice.
11601                while let Some(next_selection) = selections_iter.peek() {
11602                    let next_rows = next_selection.spanned_rows(false, &display_map);
11603                    if next_rows.start < rows.end {
11604                        rows.end = next_rows.end;
11605                        selections_iter.next().unwrap();
11606                    } else {
11607                        break;
11608                    }
11609                }
11610
11611                // Copy the text from the selected row region and splice it either at the start
11612                // or end of the region.
11613                let start = Point::new(rows.start.0, 0);
11614                let end = Point::new(
11615                    rows.end.previous_row().0,
11616                    buffer.line_len(rows.end.previous_row()),
11617                );
11618
11619                let mut text = buffer.text_for_range(start..end).collect::<String>();
11620
11621                let insert_location = if upwards {
11622                    // When duplicating upward, we need to insert before the current line.
11623                    // If we're on the last line and it doesn't end with a newline,
11624                    // we need to add a newline before the duplicated content.
11625                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11626                        && buffer.max_point().column > 0
11627                        && !text.ends_with('\n');
11628
11629                    if needs_leading_newline {
11630                        text.insert(0, '\n');
11631                        end
11632                    } else {
11633                        text.push('\n');
11634                        Point::new(rows.start.0, 0)
11635                    }
11636                } else {
11637                    text.push('\n');
11638                    start
11639                };
11640                edits.push((insert_location..insert_location, text));
11641            } else {
11642                // duplicate character-wise
11643                let start = selection.start;
11644                let end = selection.end;
11645                let text = buffer.text_for_range(start..end).collect::<String>();
11646                edits.push((selection.end..selection.end, text));
11647            }
11648        }
11649
11650        self.transact(window, cx, |this, window, cx| {
11651            this.buffer.update(cx, |buffer, cx| {
11652                buffer.edit(edits, None, cx);
11653            });
11654
11655            // When duplicating upward with whole lines, move the cursor to the duplicated line
11656            if upwards && whole_lines {
11657                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11658
11659                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11660                    let mut new_ranges = Vec::new();
11661                    let selections = s.all::<Point>(&display_map);
11662                    let mut selections_iter = selections.iter().peekable();
11663
11664                    while let Some(first_selection) = selections_iter.next() {
11665                        // Group contiguous selections together to find the total row span
11666                        let mut group_selections = vec![first_selection];
11667                        let mut rows = first_selection.spanned_rows(false, &display_map);
11668
11669                        while let Some(next_selection) = selections_iter.peek() {
11670                            let next_rows = next_selection.spanned_rows(false, &display_map);
11671                            if next_rows.start < rows.end {
11672                                rows.end = next_rows.end;
11673                                group_selections.push(selections_iter.next().unwrap());
11674                            } else {
11675                                break;
11676                            }
11677                        }
11678
11679                        let row_count = rows.end.0 - rows.start.0;
11680
11681                        // Move all selections in this group up by the total number of duplicated rows
11682                        for selection in group_selections {
11683                            let new_start = Point::new(
11684                                selection.start.row.saturating_sub(row_count),
11685                                selection.start.column,
11686                            );
11687
11688                            let new_end = Point::new(
11689                                selection.end.row.saturating_sub(row_count),
11690                                selection.end.column,
11691                            );
11692
11693                            new_ranges.push(new_start..new_end);
11694                        }
11695                    }
11696
11697                    s.select_ranges(new_ranges);
11698                });
11699            }
11700
11701            this.request_autoscroll(Autoscroll::fit(), cx);
11702        });
11703    }
11704
11705    pub fn duplicate_line_up(
11706        &mut self,
11707        _: &DuplicateLineUp,
11708        window: &mut Window,
11709        cx: &mut Context<Self>,
11710    ) {
11711        self.duplicate(true, true, window, cx);
11712    }
11713
11714    pub fn duplicate_line_down(
11715        &mut self,
11716        _: &DuplicateLineDown,
11717        window: &mut Window,
11718        cx: &mut Context<Self>,
11719    ) {
11720        self.duplicate(false, true, window, cx);
11721    }
11722
11723    pub fn duplicate_selection(
11724        &mut self,
11725        _: &DuplicateSelection,
11726        window: &mut Window,
11727        cx: &mut Context<Self>,
11728    ) {
11729        self.duplicate(false, false, window, cx);
11730    }
11731
11732    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11733        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11734        if self.mode.is_single_line() {
11735            cx.propagate();
11736            return;
11737        }
11738
11739        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11740        let buffer = self.buffer.read(cx).snapshot(cx);
11741
11742        let mut edits = Vec::new();
11743        let mut unfold_ranges = Vec::new();
11744        let mut refold_creases = Vec::new();
11745
11746        let selections = self.selections.all::<Point>(&display_map);
11747        let mut selections = selections.iter().peekable();
11748        let mut contiguous_row_selections = Vec::new();
11749        let mut new_selections = Vec::new();
11750
11751        while let Some(selection) = selections.next() {
11752            // Find all the selections that span a contiguous row range
11753            let (start_row, end_row) = consume_contiguous_rows(
11754                &mut contiguous_row_selections,
11755                selection,
11756                &display_map,
11757                &mut selections,
11758            );
11759
11760            // Move the text spanned by the row range to be before the line preceding the row range
11761            if start_row.0 > 0 {
11762                let range_to_move = Point::new(
11763                    start_row.previous_row().0,
11764                    buffer.line_len(start_row.previous_row()),
11765                )
11766                    ..Point::new(
11767                        end_row.previous_row().0,
11768                        buffer.line_len(end_row.previous_row()),
11769                    );
11770                let insertion_point = display_map
11771                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11772                    .0;
11773
11774                // Don't move lines across excerpts
11775                if buffer
11776                    .excerpt_containing(insertion_point..range_to_move.end)
11777                    .is_some()
11778                {
11779                    let text = buffer
11780                        .text_for_range(range_to_move.clone())
11781                        .flat_map(|s| s.chars())
11782                        .skip(1)
11783                        .chain(['\n'])
11784                        .collect::<String>();
11785
11786                    edits.push((
11787                        buffer.anchor_after(range_to_move.start)
11788                            ..buffer.anchor_before(range_to_move.end),
11789                        String::new(),
11790                    ));
11791                    let insertion_anchor = buffer.anchor_after(insertion_point);
11792                    edits.push((insertion_anchor..insertion_anchor, text));
11793
11794                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11795
11796                    // Move selections up
11797                    new_selections.extend(contiguous_row_selections.drain(..).map(
11798                        |mut selection| {
11799                            selection.start.row -= row_delta;
11800                            selection.end.row -= row_delta;
11801                            selection
11802                        },
11803                    ));
11804
11805                    // Move folds up
11806                    unfold_ranges.push(range_to_move.clone());
11807                    for fold in display_map.folds_in_range(
11808                        buffer.anchor_before(range_to_move.start)
11809                            ..buffer.anchor_after(range_to_move.end),
11810                    ) {
11811                        let mut start = fold.range.start.to_point(&buffer);
11812                        let mut end = fold.range.end.to_point(&buffer);
11813                        start.row -= row_delta;
11814                        end.row -= row_delta;
11815                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11816                    }
11817                }
11818            }
11819
11820            // If we didn't move line(s), preserve the existing selections
11821            new_selections.append(&mut contiguous_row_selections);
11822        }
11823
11824        self.transact(window, cx, |this, window, cx| {
11825            this.unfold_ranges(&unfold_ranges, true, true, cx);
11826            this.buffer.update(cx, |buffer, cx| {
11827                for (range, text) in edits {
11828                    buffer.edit([(range, text)], None, cx);
11829                }
11830            });
11831            this.fold_creases(refold_creases, true, window, cx);
11832            this.change_selections(Default::default(), window, cx, |s| {
11833                s.select(new_selections);
11834            })
11835        });
11836    }
11837
11838    pub fn move_line_down(
11839        &mut self,
11840        _: &MoveLineDown,
11841        window: &mut Window,
11842        cx: &mut Context<Self>,
11843    ) {
11844        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11845        if self.mode.is_single_line() {
11846            cx.propagate();
11847            return;
11848        }
11849
11850        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11851        let buffer = self.buffer.read(cx).snapshot(cx);
11852
11853        let mut edits = Vec::new();
11854        let mut unfold_ranges = Vec::new();
11855        let mut refold_creases = Vec::new();
11856
11857        let selections = self.selections.all::<Point>(&display_map);
11858        let mut selections = selections.iter().peekable();
11859        let mut contiguous_row_selections = Vec::new();
11860        let mut new_selections = Vec::new();
11861
11862        while let Some(selection) = selections.next() {
11863            // Find all the selections that span a contiguous row range
11864            let (start_row, end_row) = consume_contiguous_rows(
11865                &mut contiguous_row_selections,
11866                selection,
11867                &display_map,
11868                &mut selections,
11869            );
11870
11871            // Move the text spanned by the row range to be after the last line of the row range
11872            if end_row.0 <= buffer.max_point().row {
11873                let range_to_move =
11874                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11875                let insertion_point = display_map
11876                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11877                    .0;
11878
11879                // Don't move lines across excerpt boundaries
11880                if buffer
11881                    .excerpt_containing(range_to_move.start..insertion_point)
11882                    .is_some()
11883                {
11884                    let mut text = String::from("\n");
11885                    text.extend(buffer.text_for_range(range_to_move.clone()));
11886                    text.pop(); // Drop trailing newline
11887                    edits.push((
11888                        buffer.anchor_after(range_to_move.start)
11889                            ..buffer.anchor_before(range_to_move.end),
11890                        String::new(),
11891                    ));
11892                    let insertion_anchor = buffer.anchor_after(insertion_point);
11893                    edits.push((insertion_anchor..insertion_anchor, text));
11894
11895                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11896
11897                    // Move selections down
11898                    new_selections.extend(contiguous_row_selections.drain(..).map(
11899                        |mut selection| {
11900                            selection.start.row += row_delta;
11901                            selection.end.row += row_delta;
11902                            selection
11903                        },
11904                    ));
11905
11906                    // Move folds down
11907                    unfold_ranges.push(range_to_move.clone());
11908                    for fold in display_map.folds_in_range(
11909                        buffer.anchor_before(range_to_move.start)
11910                            ..buffer.anchor_after(range_to_move.end),
11911                    ) {
11912                        let mut start = fold.range.start.to_point(&buffer);
11913                        let mut end = fold.range.end.to_point(&buffer);
11914                        start.row += row_delta;
11915                        end.row += row_delta;
11916                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11917                    }
11918                }
11919            }
11920
11921            // If we didn't move line(s), preserve the existing selections
11922            new_selections.append(&mut contiguous_row_selections);
11923        }
11924
11925        self.transact(window, cx, |this, window, cx| {
11926            this.unfold_ranges(&unfold_ranges, true, true, cx);
11927            this.buffer.update(cx, |buffer, cx| {
11928                for (range, text) in edits {
11929                    buffer.edit([(range, text)], None, cx);
11930                }
11931            });
11932            this.fold_creases(refold_creases, true, window, cx);
11933            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11934        });
11935    }
11936
11937    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11938        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11939        let text_layout_details = &self.text_layout_details(window);
11940        self.transact(window, cx, |this, window, cx| {
11941            let edits = this.change_selections(Default::default(), window, cx, |s| {
11942                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11943                s.move_with(|display_map, selection| {
11944                    if !selection.is_empty() {
11945                        return;
11946                    }
11947
11948                    let mut head = selection.head();
11949                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11950                    if head.column() == display_map.line_len(head.row()) {
11951                        transpose_offset = display_map
11952                            .buffer_snapshot()
11953                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11954                    }
11955
11956                    if transpose_offset == 0 {
11957                        return;
11958                    }
11959
11960                    *head.column_mut() += 1;
11961                    head = display_map.clip_point(head, Bias::Right);
11962                    let goal = SelectionGoal::HorizontalPosition(
11963                        display_map
11964                            .x_for_display_point(head, text_layout_details)
11965                            .into(),
11966                    );
11967                    selection.collapse_to(head, goal);
11968
11969                    let transpose_start = display_map
11970                        .buffer_snapshot()
11971                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11972                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11973                        let transpose_end = display_map
11974                            .buffer_snapshot()
11975                            .clip_offset(transpose_offset + 1, Bias::Right);
11976                        if let Some(ch) = display_map
11977                            .buffer_snapshot()
11978                            .chars_at(transpose_start)
11979                            .next()
11980                        {
11981                            edits.push((transpose_start..transpose_offset, String::new()));
11982                            edits.push((transpose_end..transpose_end, ch.to_string()));
11983                        }
11984                    }
11985                });
11986                edits
11987            });
11988            this.buffer
11989                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11990            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
11991            this.change_selections(Default::default(), window, cx, |s| {
11992                s.select(selections);
11993            });
11994        });
11995    }
11996
11997    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11998        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11999        if self.mode.is_single_line() {
12000            cx.propagate();
12001            return;
12002        }
12003
12004        self.rewrap_impl(RewrapOptions::default(), cx)
12005    }
12006
12007    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12008        let buffer = self.buffer.read(cx).snapshot(cx);
12009        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12010
12011        #[derive(Clone, Debug, PartialEq)]
12012        enum CommentFormat {
12013            /// single line comment, with prefix for line
12014            Line(String),
12015            /// single line within a block comment, with prefix for line
12016            BlockLine(String),
12017            /// a single line of a block comment that includes the initial delimiter
12018            BlockCommentWithStart(BlockCommentConfig),
12019            /// a single line of a block comment that includes the ending delimiter
12020            BlockCommentWithEnd(BlockCommentConfig),
12021        }
12022
12023        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12024        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12025            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12026                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12027                .peekable();
12028
12029            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12030                row
12031            } else {
12032                return Vec::new();
12033            };
12034
12035            let language_settings = buffer.language_settings_at(selection.head(), cx);
12036            let language_scope = buffer.language_scope_at(selection.head());
12037
12038            let indent_and_prefix_for_row =
12039                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12040                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12041                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12042                        &language_scope
12043                    {
12044                        let indent_end = Point::new(row, indent.len);
12045                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12046                        let line_text_after_indent = buffer
12047                            .text_for_range(indent_end..line_end)
12048                            .collect::<String>();
12049
12050                        let is_within_comment_override = buffer
12051                            .language_scope_at(indent_end)
12052                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12053                        let comment_delimiters = if is_within_comment_override {
12054                            // we are within a comment syntax node, but we don't
12055                            // yet know what kind of comment: block, doc or line
12056                            match (
12057                                language_scope.documentation_comment(),
12058                                language_scope.block_comment(),
12059                            ) {
12060                                (Some(config), _) | (_, Some(config))
12061                                    if buffer.contains_str_at(indent_end, &config.start) =>
12062                                {
12063                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12064                                }
12065                                (Some(config), _) | (_, Some(config))
12066                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12067                                {
12068                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12069                                }
12070                                (Some(config), _) | (_, Some(config))
12071                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12072                                {
12073                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12074                                }
12075                                (_, _) => language_scope
12076                                    .line_comment_prefixes()
12077                                    .iter()
12078                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12079                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12080                            }
12081                        } else {
12082                            // we not in an overridden comment node, but we may
12083                            // be within a non-overridden line comment node
12084                            language_scope
12085                                .line_comment_prefixes()
12086                                .iter()
12087                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12088                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12089                        };
12090
12091                        let rewrap_prefix = language_scope
12092                            .rewrap_prefixes()
12093                            .iter()
12094                            .find_map(|prefix_regex| {
12095                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12096                                    if mat.start() == 0 {
12097                                        Some(mat.as_str().to_string())
12098                                    } else {
12099                                        None
12100                                    }
12101                                })
12102                            })
12103                            .flatten();
12104                        (comment_delimiters, rewrap_prefix)
12105                    } else {
12106                        (None, None)
12107                    };
12108                    (indent, comment_prefix, rewrap_prefix)
12109                };
12110
12111            let mut ranges = Vec::new();
12112            let from_empty_selection = selection.is_empty();
12113
12114            let mut current_range_start = first_row;
12115            let mut prev_row = first_row;
12116            let (
12117                mut current_range_indent,
12118                mut current_range_comment_delimiters,
12119                mut current_range_rewrap_prefix,
12120            ) = indent_and_prefix_for_row(first_row);
12121
12122            for row in non_blank_rows_iter.skip(1) {
12123                let has_paragraph_break = row > prev_row + 1;
12124
12125                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12126                    indent_and_prefix_for_row(row);
12127
12128                let has_indent_change = row_indent != current_range_indent;
12129                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12130
12131                let has_boundary_change = has_comment_change
12132                    || row_rewrap_prefix.is_some()
12133                    || (has_indent_change && current_range_comment_delimiters.is_some());
12134
12135                if has_paragraph_break || has_boundary_change {
12136                    ranges.push((
12137                        language_settings.clone(),
12138                        Point::new(current_range_start, 0)
12139                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12140                        current_range_indent,
12141                        current_range_comment_delimiters.clone(),
12142                        current_range_rewrap_prefix.clone(),
12143                        from_empty_selection,
12144                    ));
12145                    current_range_start = row;
12146                    current_range_indent = row_indent;
12147                    current_range_comment_delimiters = row_comment_delimiters;
12148                    current_range_rewrap_prefix = row_rewrap_prefix;
12149                }
12150                prev_row = row;
12151            }
12152
12153            ranges.push((
12154                language_settings.clone(),
12155                Point::new(current_range_start, 0)
12156                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12157                current_range_indent,
12158                current_range_comment_delimiters,
12159                current_range_rewrap_prefix,
12160                from_empty_selection,
12161            ));
12162
12163            ranges
12164        });
12165
12166        let mut edits = Vec::new();
12167        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12168
12169        for (
12170            language_settings,
12171            wrap_range,
12172            mut indent_size,
12173            comment_prefix,
12174            rewrap_prefix,
12175            from_empty_selection,
12176        ) in wrap_ranges
12177        {
12178            let mut start_row = wrap_range.start.row;
12179            let mut end_row = wrap_range.end.row;
12180
12181            // Skip selections that overlap with a range that has already been rewrapped.
12182            let selection_range = start_row..end_row;
12183            if rewrapped_row_ranges
12184                .iter()
12185                .any(|range| range.overlaps(&selection_range))
12186            {
12187                continue;
12188            }
12189
12190            let tab_size = language_settings.tab_size;
12191
12192            let (line_prefix, inside_comment) = match &comment_prefix {
12193                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12194                    (Some(prefix.as_str()), true)
12195                }
12196                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12197                    (Some(prefix.as_ref()), true)
12198                }
12199                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12200                    start: _,
12201                    end: _,
12202                    prefix,
12203                    tab_size,
12204                })) => {
12205                    indent_size.len += tab_size;
12206                    (Some(prefix.as_ref()), true)
12207                }
12208                None => (None, false),
12209            };
12210            let indent_prefix = indent_size.chars().collect::<String>();
12211            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12212
12213            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12214                RewrapBehavior::InComments => inside_comment,
12215                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12216                RewrapBehavior::Anywhere => true,
12217            };
12218
12219            let should_rewrap = options.override_language_settings
12220                || allow_rewrap_based_on_language
12221                || self.hard_wrap.is_some();
12222            if !should_rewrap {
12223                continue;
12224            }
12225
12226            if from_empty_selection {
12227                'expand_upwards: while start_row > 0 {
12228                    let prev_row = start_row - 1;
12229                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12230                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12231                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12232                    {
12233                        start_row = prev_row;
12234                    } else {
12235                        break 'expand_upwards;
12236                    }
12237                }
12238
12239                'expand_downwards: while end_row < buffer.max_point().row {
12240                    let next_row = end_row + 1;
12241                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12242                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12243                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12244                    {
12245                        end_row = next_row;
12246                    } else {
12247                        break 'expand_downwards;
12248                    }
12249                }
12250            }
12251
12252            let start = Point::new(start_row, 0);
12253            let start_offset = ToOffset::to_offset(&start, &buffer);
12254            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12255            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12256            let mut first_line_delimiter = None;
12257            let mut last_line_delimiter = None;
12258            let Some(lines_without_prefixes) = selection_text
12259                .lines()
12260                .enumerate()
12261                .map(|(ix, line)| {
12262                    let line_trimmed = line.trim_start();
12263                    if rewrap_prefix.is_some() && ix > 0 {
12264                        Ok(line_trimmed)
12265                    } else if let Some(
12266                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12267                            start,
12268                            prefix,
12269                            end,
12270                            tab_size,
12271                        })
12272                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12273                            start,
12274                            prefix,
12275                            end,
12276                            tab_size,
12277                        }),
12278                    ) = &comment_prefix
12279                    {
12280                        let line_trimmed = line_trimmed
12281                            .strip_prefix(start.as_ref())
12282                            .map(|s| {
12283                                let mut indent_size = indent_size;
12284                                indent_size.len -= tab_size;
12285                                let indent_prefix: String = indent_size.chars().collect();
12286                                first_line_delimiter = Some((indent_prefix, start));
12287                                s.trim_start()
12288                            })
12289                            .unwrap_or(line_trimmed);
12290                        let line_trimmed = line_trimmed
12291                            .strip_suffix(end.as_ref())
12292                            .map(|s| {
12293                                last_line_delimiter = Some(end);
12294                                s.trim_end()
12295                            })
12296                            .unwrap_or(line_trimmed);
12297                        let line_trimmed = line_trimmed
12298                            .strip_prefix(prefix.as_ref())
12299                            .unwrap_or(line_trimmed);
12300                        Ok(line_trimmed)
12301                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12302                        line_trimmed.strip_prefix(prefix).with_context(|| {
12303                            format!("line did not start with prefix {prefix:?}: {line:?}")
12304                        })
12305                    } else {
12306                        line_trimmed
12307                            .strip_prefix(&line_prefix.trim_start())
12308                            .with_context(|| {
12309                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12310                            })
12311                    }
12312                })
12313                .collect::<Result<Vec<_>, _>>()
12314                .log_err()
12315            else {
12316                continue;
12317            };
12318
12319            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12320                buffer
12321                    .language_settings_at(Point::new(start_row, 0), cx)
12322                    .preferred_line_length as usize
12323            });
12324
12325            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12326                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12327            } else {
12328                line_prefix.clone()
12329            };
12330
12331            let wrapped_text = {
12332                let mut wrapped_text = wrap_with_prefix(
12333                    line_prefix,
12334                    subsequent_lines_prefix,
12335                    lines_without_prefixes.join("\n"),
12336                    wrap_column,
12337                    tab_size,
12338                    options.preserve_existing_whitespace,
12339                );
12340
12341                if let Some((indent, delimiter)) = first_line_delimiter {
12342                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12343                }
12344                if let Some(last_line) = last_line_delimiter {
12345                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12346                }
12347
12348                wrapped_text
12349            };
12350
12351            // TODO: should always use char-based diff while still supporting cursor behavior that
12352            // matches vim.
12353            let mut diff_options = DiffOptions::default();
12354            if options.override_language_settings {
12355                diff_options.max_word_diff_len = 0;
12356                diff_options.max_word_diff_line_count = 0;
12357            } else {
12358                diff_options.max_word_diff_len = usize::MAX;
12359                diff_options.max_word_diff_line_count = usize::MAX;
12360            }
12361
12362            for (old_range, new_text) in
12363                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12364            {
12365                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12366                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12367                edits.push((edit_start..edit_end, new_text));
12368            }
12369
12370            rewrapped_row_ranges.push(start_row..=end_row);
12371        }
12372
12373        self.buffer
12374            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12375    }
12376
12377    pub fn cut_common(
12378        &mut self,
12379        cut_no_selection_line: bool,
12380        window: &mut Window,
12381        cx: &mut Context<Self>,
12382    ) -> ClipboardItem {
12383        let mut text = String::new();
12384        let buffer = self.buffer.read(cx).snapshot(cx);
12385        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12386        let mut clipboard_selections = Vec::with_capacity(selections.len());
12387        {
12388            let max_point = buffer.max_point();
12389            let mut is_first = true;
12390            for selection in &mut selections {
12391                let is_entire_line =
12392                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12393                if is_entire_line {
12394                    selection.start = Point::new(selection.start.row, 0);
12395                    if !selection.is_empty() && selection.end.column == 0 {
12396                        selection.end = cmp::min(max_point, selection.end);
12397                    } else {
12398                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12399                    }
12400                    selection.goal = SelectionGoal::None;
12401                }
12402                if is_first {
12403                    is_first = false;
12404                } else {
12405                    text += "\n";
12406                }
12407                let mut len = 0;
12408                for chunk in buffer.text_for_range(selection.start..selection.end) {
12409                    text.push_str(chunk);
12410                    len += chunk.len();
12411                }
12412                clipboard_selections.push(ClipboardSelection {
12413                    len,
12414                    is_entire_line,
12415                    first_line_indent: buffer
12416                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12417                        .len,
12418                });
12419            }
12420        }
12421
12422        self.transact(window, cx, |this, window, cx| {
12423            this.change_selections(Default::default(), window, cx, |s| {
12424                s.select(selections);
12425            });
12426            this.insert("", window, cx);
12427        });
12428        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12429    }
12430
12431    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12432        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12433        let item = self.cut_common(true, window, cx);
12434        cx.write_to_clipboard(item);
12435    }
12436
12437    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12438        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12439        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12440            s.move_with(|snapshot, sel| {
12441                if sel.is_empty() {
12442                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12443                }
12444                if sel.is_empty() {
12445                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12446                }
12447            });
12448        });
12449        let item = self.cut_common(false, window, cx);
12450        cx.set_global(KillRing(item))
12451    }
12452
12453    pub fn kill_ring_yank(
12454        &mut self,
12455        _: &KillRingYank,
12456        window: &mut Window,
12457        cx: &mut Context<Self>,
12458    ) {
12459        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12460        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12461            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12462                (kill_ring.text().to_string(), kill_ring.metadata_json())
12463            } else {
12464                return;
12465            }
12466        } else {
12467            return;
12468        };
12469        self.do_paste(&text, metadata, false, window, cx);
12470    }
12471
12472    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12473        self.do_copy(true, cx);
12474    }
12475
12476    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12477        self.do_copy(false, cx);
12478    }
12479
12480    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12481        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12482        let buffer = self.buffer.read(cx).read(cx);
12483        let mut text = String::new();
12484
12485        let mut clipboard_selections = Vec::with_capacity(selections.len());
12486        {
12487            let max_point = buffer.max_point();
12488            let mut is_first = true;
12489            for selection in &selections {
12490                let mut start = selection.start;
12491                let mut end = selection.end;
12492                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12493                let mut add_trailing_newline = false;
12494                if is_entire_line {
12495                    start = Point::new(start.row, 0);
12496                    let next_line_start = Point::new(end.row + 1, 0);
12497                    if next_line_start <= max_point {
12498                        end = next_line_start;
12499                    } else {
12500                        // We're on the last line without a trailing newline.
12501                        // Copy to the end of the line and add a newline afterwards.
12502                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12503                        add_trailing_newline = true;
12504                    }
12505                }
12506
12507                let mut trimmed_selections = Vec::new();
12508                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12509                    let row = MultiBufferRow(start.row);
12510                    let first_indent = buffer.indent_size_for_line(row);
12511                    if first_indent.len == 0 || start.column > first_indent.len {
12512                        trimmed_selections.push(start..end);
12513                    } else {
12514                        trimmed_selections.push(
12515                            Point::new(row.0, first_indent.len)
12516                                ..Point::new(row.0, buffer.line_len(row)),
12517                        );
12518                        for row in start.row + 1..=end.row {
12519                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12520                            if row == end.row {
12521                                line_len = end.column;
12522                            }
12523                            if line_len == 0 {
12524                                trimmed_selections
12525                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12526                                continue;
12527                            }
12528                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12529                            if row_indent_size.len >= first_indent.len {
12530                                trimmed_selections.push(
12531                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12532                                );
12533                            } else {
12534                                trimmed_selections.clear();
12535                                trimmed_selections.push(start..end);
12536                                break;
12537                            }
12538                        }
12539                    }
12540                } else {
12541                    trimmed_selections.push(start..end);
12542                }
12543
12544                for trimmed_range in trimmed_selections {
12545                    if is_first {
12546                        is_first = false;
12547                    } else {
12548                        text += "\n";
12549                    }
12550                    let mut len = 0;
12551                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12552                        text.push_str(chunk);
12553                        len += chunk.len();
12554                    }
12555                    if add_trailing_newline {
12556                        text.push('\n');
12557                        len += 1;
12558                    }
12559                    clipboard_selections.push(ClipboardSelection {
12560                        len,
12561                        is_entire_line,
12562                        first_line_indent: buffer
12563                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12564                            .len,
12565                    });
12566                }
12567            }
12568        }
12569
12570        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12571            text,
12572            clipboard_selections,
12573        ));
12574    }
12575
12576    pub fn do_paste(
12577        &mut self,
12578        text: &String,
12579        clipboard_selections: Option<Vec<ClipboardSelection>>,
12580        handle_entire_lines: bool,
12581        window: &mut Window,
12582        cx: &mut Context<Self>,
12583    ) {
12584        if self.read_only(cx) {
12585            return;
12586        }
12587
12588        let clipboard_text = Cow::Borrowed(text.as_str());
12589
12590        self.transact(window, cx, |this, window, cx| {
12591            let had_active_edit_prediction = this.has_active_edit_prediction();
12592            let display_map = this.display_snapshot(cx);
12593            let old_selections = this.selections.all::<usize>(&display_map);
12594            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12595
12596            if let Some(mut clipboard_selections) = clipboard_selections {
12597                let all_selections_were_entire_line =
12598                    clipboard_selections.iter().all(|s| s.is_entire_line);
12599                let first_selection_indent_column =
12600                    clipboard_selections.first().map(|s| s.first_line_indent);
12601                if clipboard_selections.len() != old_selections.len() {
12602                    clipboard_selections.drain(..);
12603                }
12604                let mut auto_indent_on_paste = true;
12605
12606                this.buffer.update(cx, |buffer, cx| {
12607                    let snapshot = buffer.read(cx);
12608                    auto_indent_on_paste = snapshot
12609                        .language_settings_at(cursor_offset, cx)
12610                        .auto_indent_on_paste;
12611
12612                    let mut start_offset = 0;
12613                    let mut edits = Vec::new();
12614                    let mut original_indent_columns = Vec::new();
12615                    for (ix, selection) in old_selections.iter().enumerate() {
12616                        let to_insert;
12617                        let entire_line;
12618                        let original_indent_column;
12619                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12620                            let end_offset = start_offset + clipboard_selection.len;
12621                            to_insert = &clipboard_text[start_offset..end_offset];
12622                            entire_line = clipboard_selection.is_entire_line;
12623                            start_offset = end_offset + 1;
12624                            original_indent_column = Some(clipboard_selection.first_line_indent);
12625                        } else {
12626                            to_insert = &*clipboard_text;
12627                            entire_line = all_selections_were_entire_line;
12628                            original_indent_column = first_selection_indent_column
12629                        }
12630
12631                        let (range, to_insert) =
12632                            if selection.is_empty() && handle_entire_lines && entire_line {
12633                                // If the corresponding selection was empty when this slice of the
12634                                // clipboard text was written, then the entire line containing the
12635                                // selection was copied. If this selection is also currently empty,
12636                                // then paste the line before the current line of the buffer.
12637                                let column = selection.start.to_point(&snapshot).column as usize;
12638                                let line_start = selection.start - column;
12639                                (line_start..line_start, Cow::Borrowed(to_insert))
12640                            } else {
12641                                let language = snapshot.language_at(selection.head());
12642                                let range = selection.range();
12643                                if let Some(language) = language
12644                                    && language.name() == "Markdown".into()
12645                                {
12646                                    edit_for_markdown_paste(
12647                                        &snapshot,
12648                                        range,
12649                                        to_insert,
12650                                        url::Url::parse(to_insert).ok(),
12651                                    )
12652                                } else {
12653                                    (range, Cow::Borrowed(to_insert))
12654                                }
12655                            };
12656
12657                        edits.push((range, to_insert));
12658                        original_indent_columns.push(original_indent_column);
12659                    }
12660                    drop(snapshot);
12661
12662                    buffer.edit(
12663                        edits,
12664                        if auto_indent_on_paste {
12665                            Some(AutoindentMode::Block {
12666                                original_indent_columns,
12667                            })
12668                        } else {
12669                            None
12670                        },
12671                        cx,
12672                    );
12673                });
12674
12675                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12676                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12677            } else {
12678                let url = url::Url::parse(&clipboard_text).ok();
12679
12680                let auto_indent_mode = if !clipboard_text.is_empty() {
12681                    Some(AutoindentMode::Block {
12682                        original_indent_columns: Vec::new(),
12683                    })
12684                } else {
12685                    None
12686                };
12687
12688                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12689                    let snapshot = buffer.snapshot(cx);
12690
12691                    let anchors = old_selections
12692                        .iter()
12693                        .map(|s| {
12694                            let anchor = snapshot.anchor_after(s.head());
12695                            s.map(|_| anchor)
12696                        })
12697                        .collect::<Vec<_>>();
12698
12699                    let mut edits = Vec::new();
12700
12701                    for selection in old_selections.iter() {
12702                        let language = snapshot.language_at(selection.head());
12703                        let range = selection.range();
12704
12705                        let (edit_range, edit_text) = if let Some(language) = language
12706                            && language.name() == "Markdown".into()
12707                        {
12708                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12709                        } else {
12710                            (range, clipboard_text.clone())
12711                        };
12712
12713                        edits.push((edit_range, edit_text));
12714                    }
12715
12716                    drop(snapshot);
12717                    buffer.edit(edits, auto_indent_mode, cx);
12718
12719                    anchors
12720                });
12721
12722                this.change_selections(Default::default(), window, cx, |s| {
12723                    s.select_anchors(selection_anchors);
12724                });
12725            }
12726
12727            let trigger_in_words =
12728                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12729
12730            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12731        });
12732    }
12733
12734    pub fn diff_clipboard_with_selection(
12735        &mut self,
12736        _: &DiffClipboardWithSelection,
12737        window: &mut Window,
12738        cx: &mut Context<Self>,
12739    ) {
12740        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12741
12742        if selections.is_empty() {
12743            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12744            return;
12745        };
12746
12747        let clipboard_text = match cx.read_from_clipboard() {
12748            Some(item) => match item.entries().first() {
12749                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12750                _ => None,
12751            },
12752            None => None,
12753        };
12754
12755        let Some(clipboard_text) = clipboard_text else {
12756            log::warn!("Clipboard doesn't contain text.");
12757            return;
12758        };
12759
12760        window.dispatch_action(
12761            Box::new(DiffClipboardWithSelectionData {
12762                clipboard_text,
12763                editor: cx.entity(),
12764            }),
12765            cx,
12766        );
12767    }
12768
12769    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12770        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12771        if let Some(item) = cx.read_from_clipboard() {
12772            let entries = item.entries();
12773
12774            match entries.first() {
12775                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12776                // of all the pasted entries.
12777                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12778                    .do_paste(
12779                        clipboard_string.text(),
12780                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12781                        true,
12782                        window,
12783                        cx,
12784                    ),
12785                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12786            }
12787        }
12788    }
12789
12790    pub fn undo(&mut self, _: &Undo, 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.undo(cx)) {
12798            if let 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 undo. \
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            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12817        }
12818    }
12819
12820    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12821        if self.read_only(cx) {
12822            return;
12823        }
12824
12825        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12826
12827        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12828            if let Some((_, Some(selections))) =
12829                self.selection_history.transaction(transaction_id).cloned()
12830            {
12831                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12832                    s.select_anchors(selections.to_vec());
12833                });
12834            } else {
12835                log::error!(
12836                    "No entry in selection_history found for redo. \
12837                     This may correspond to a bug where undo does not update the selection. \
12838                     If this is occurring, please add details to \
12839                     https://github.com/zed-industries/zed/issues/22692"
12840                );
12841            }
12842            self.request_autoscroll(Autoscroll::fit(), cx);
12843            self.unmark_text(window, cx);
12844            self.refresh_edit_prediction(true, false, window, cx);
12845            cx.emit(EditorEvent::Edited { transaction_id });
12846        }
12847    }
12848
12849    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12850        self.buffer
12851            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12852    }
12853
12854    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12855        self.buffer
12856            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12857    }
12858
12859    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12860        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12861        self.change_selections(Default::default(), window, cx, |s| {
12862            s.move_with(|map, selection| {
12863                let cursor = if selection.is_empty() {
12864                    movement::left(map, selection.start)
12865                } else {
12866                    selection.start
12867                };
12868                selection.collapse_to(cursor, SelectionGoal::None);
12869            });
12870        })
12871    }
12872
12873    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12874        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12875        self.change_selections(Default::default(), window, cx, |s| {
12876            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12877        })
12878    }
12879
12880    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12881        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12882        self.change_selections(Default::default(), window, cx, |s| {
12883            s.move_with(|map, selection| {
12884                let cursor = if selection.is_empty() {
12885                    movement::right(map, selection.end)
12886                } else {
12887                    selection.end
12888                };
12889                selection.collapse_to(cursor, SelectionGoal::None)
12890            });
12891        })
12892    }
12893
12894    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12895        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12896        self.change_selections(Default::default(), window, cx, |s| {
12897            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12898        });
12899    }
12900
12901    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12902        if self.take_rename(true, window, cx).is_some() {
12903            return;
12904        }
12905
12906        if self.mode.is_single_line() {
12907            cx.propagate();
12908            return;
12909        }
12910
12911        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12912
12913        let text_layout_details = &self.text_layout_details(window);
12914        let selection_count = self.selections.count();
12915        let first_selection = self.selections.first_anchor();
12916
12917        self.change_selections(Default::default(), window, cx, |s| {
12918            s.move_with(|map, selection| {
12919                if !selection.is_empty() {
12920                    selection.goal = SelectionGoal::None;
12921                }
12922                let (cursor, goal) = movement::up(
12923                    map,
12924                    selection.start,
12925                    selection.goal,
12926                    false,
12927                    text_layout_details,
12928                );
12929                selection.collapse_to(cursor, goal);
12930            });
12931        });
12932
12933        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12934        {
12935            cx.propagate();
12936        }
12937    }
12938
12939    pub fn move_up_by_lines(
12940        &mut self,
12941        action: &MoveUpByLines,
12942        window: &mut Window,
12943        cx: &mut Context<Self>,
12944    ) {
12945        if self.take_rename(true, window, cx).is_some() {
12946            return;
12947        }
12948
12949        if self.mode.is_single_line() {
12950            cx.propagate();
12951            return;
12952        }
12953
12954        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12955
12956        let text_layout_details = &self.text_layout_details(window);
12957
12958        self.change_selections(Default::default(), window, cx, |s| {
12959            s.move_with(|map, selection| {
12960                if !selection.is_empty() {
12961                    selection.goal = SelectionGoal::None;
12962                }
12963                let (cursor, goal) = movement::up_by_rows(
12964                    map,
12965                    selection.start,
12966                    action.lines,
12967                    selection.goal,
12968                    false,
12969                    text_layout_details,
12970                );
12971                selection.collapse_to(cursor, goal);
12972            });
12973        })
12974    }
12975
12976    pub fn move_down_by_lines(
12977        &mut self,
12978        action: &MoveDownByLines,
12979        window: &mut Window,
12980        cx: &mut Context<Self>,
12981    ) {
12982        if self.take_rename(true, window, cx).is_some() {
12983            return;
12984        }
12985
12986        if self.mode.is_single_line() {
12987            cx.propagate();
12988            return;
12989        }
12990
12991        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12992
12993        let text_layout_details = &self.text_layout_details(window);
12994
12995        self.change_selections(Default::default(), window, cx, |s| {
12996            s.move_with(|map, selection| {
12997                if !selection.is_empty() {
12998                    selection.goal = SelectionGoal::None;
12999                }
13000                let (cursor, goal) = movement::down_by_rows(
13001                    map,
13002                    selection.start,
13003                    action.lines,
13004                    selection.goal,
13005                    false,
13006                    text_layout_details,
13007                );
13008                selection.collapse_to(cursor, goal);
13009            });
13010        })
13011    }
13012
13013    pub fn select_down_by_lines(
13014        &mut self,
13015        action: &SelectDownByLines,
13016        window: &mut Window,
13017        cx: &mut Context<Self>,
13018    ) {
13019        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13020        let text_layout_details = &self.text_layout_details(window);
13021        self.change_selections(Default::default(), window, cx, |s| {
13022            s.move_heads_with(|map, head, goal| {
13023                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13024            })
13025        })
13026    }
13027
13028    pub fn select_up_by_lines(
13029        &mut self,
13030        action: &SelectUpByLines,
13031        window: &mut Window,
13032        cx: &mut Context<Self>,
13033    ) {
13034        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13035        let text_layout_details = &self.text_layout_details(window);
13036        self.change_selections(Default::default(), window, cx, |s| {
13037            s.move_heads_with(|map, head, goal| {
13038                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13039            })
13040        })
13041    }
13042
13043    pub fn select_page_up(
13044        &mut self,
13045        _: &SelectPageUp,
13046        window: &mut Window,
13047        cx: &mut Context<Self>,
13048    ) {
13049        let Some(row_count) = self.visible_row_count() else {
13050            return;
13051        };
13052
13053        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13054
13055        let text_layout_details = &self.text_layout_details(window);
13056
13057        self.change_selections(Default::default(), window, cx, |s| {
13058            s.move_heads_with(|map, head, goal| {
13059                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13060            })
13061        })
13062    }
13063
13064    pub fn move_page_up(
13065        &mut self,
13066        action: &MovePageUp,
13067        window: &mut Window,
13068        cx: &mut Context<Self>,
13069    ) {
13070        if self.take_rename(true, window, cx).is_some() {
13071            return;
13072        }
13073
13074        if self
13075            .context_menu
13076            .borrow_mut()
13077            .as_mut()
13078            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13079            .unwrap_or(false)
13080        {
13081            return;
13082        }
13083
13084        if matches!(self.mode, EditorMode::SingleLine) {
13085            cx.propagate();
13086            return;
13087        }
13088
13089        let Some(row_count) = self.visible_row_count() else {
13090            return;
13091        };
13092
13093        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13094
13095        let effects = if action.center_cursor {
13096            SelectionEffects::scroll(Autoscroll::center())
13097        } else {
13098            SelectionEffects::default()
13099        };
13100
13101        let text_layout_details = &self.text_layout_details(window);
13102
13103        self.change_selections(effects, window, cx, |s| {
13104            s.move_with(|map, selection| {
13105                if !selection.is_empty() {
13106                    selection.goal = SelectionGoal::None;
13107                }
13108                let (cursor, goal) = movement::up_by_rows(
13109                    map,
13110                    selection.end,
13111                    row_count,
13112                    selection.goal,
13113                    false,
13114                    text_layout_details,
13115                );
13116                selection.collapse_to(cursor, goal);
13117            });
13118        });
13119    }
13120
13121    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13122        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13123        let text_layout_details = &self.text_layout_details(window);
13124        self.change_selections(Default::default(), window, cx, |s| {
13125            s.move_heads_with(|map, head, goal| {
13126                movement::up(map, head, goal, false, text_layout_details)
13127            })
13128        })
13129    }
13130
13131    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13132        self.take_rename(true, window, cx);
13133
13134        if self.mode.is_single_line() {
13135            cx.propagate();
13136            return;
13137        }
13138
13139        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13140
13141        let text_layout_details = &self.text_layout_details(window);
13142        let selection_count = self.selections.count();
13143        let first_selection = self.selections.first_anchor();
13144
13145        self.change_selections(Default::default(), window, cx, |s| {
13146            s.move_with(|map, selection| {
13147                if !selection.is_empty() {
13148                    selection.goal = SelectionGoal::None;
13149                }
13150                let (cursor, goal) = movement::down(
13151                    map,
13152                    selection.end,
13153                    selection.goal,
13154                    false,
13155                    text_layout_details,
13156                );
13157                selection.collapse_to(cursor, goal);
13158            });
13159        });
13160
13161        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13162        {
13163            cx.propagate();
13164        }
13165    }
13166
13167    pub fn select_page_down(
13168        &mut self,
13169        _: &SelectPageDown,
13170        window: &mut Window,
13171        cx: &mut Context<Self>,
13172    ) {
13173        let Some(row_count) = self.visible_row_count() else {
13174            return;
13175        };
13176
13177        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13178
13179        let text_layout_details = &self.text_layout_details(window);
13180
13181        self.change_selections(Default::default(), window, cx, |s| {
13182            s.move_heads_with(|map, head, goal| {
13183                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13184            })
13185        })
13186    }
13187
13188    pub fn move_page_down(
13189        &mut self,
13190        action: &MovePageDown,
13191        window: &mut Window,
13192        cx: &mut Context<Self>,
13193    ) {
13194        if self.take_rename(true, window, cx).is_some() {
13195            return;
13196        }
13197
13198        if self
13199            .context_menu
13200            .borrow_mut()
13201            .as_mut()
13202            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13203            .unwrap_or(false)
13204        {
13205            return;
13206        }
13207
13208        if matches!(self.mode, EditorMode::SingleLine) {
13209            cx.propagate();
13210            return;
13211        }
13212
13213        let Some(row_count) = self.visible_row_count() else {
13214            return;
13215        };
13216
13217        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13218
13219        let effects = if action.center_cursor {
13220            SelectionEffects::scroll(Autoscroll::center())
13221        } else {
13222            SelectionEffects::default()
13223        };
13224
13225        let text_layout_details = &self.text_layout_details(window);
13226        self.change_selections(effects, window, cx, |s| {
13227            s.move_with(|map, selection| {
13228                if !selection.is_empty() {
13229                    selection.goal = SelectionGoal::None;
13230                }
13231                let (cursor, goal) = movement::down_by_rows(
13232                    map,
13233                    selection.end,
13234                    row_count,
13235                    selection.goal,
13236                    false,
13237                    text_layout_details,
13238                );
13239                selection.collapse_to(cursor, goal);
13240            });
13241        });
13242    }
13243
13244    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13245        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13246        let text_layout_details = &self.text_layout_details(window);
13247        self.change_selections(Default::default(), window, cx, |s| {
13248            s.move_heads_with(|map, head, goal| {
13249                movement::down(map, head, goal, false, text_layout_details)
13250            })
13251        });
13252    }
13253
13254    pub fn context_menu_first(
13255        &mut self,
13256        _: &ContextMenuFirst,
13257        window: &mut Window,
13258        cx: &mut Context<Self>,
13259    ) {
13260        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13261            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13262        }
13263    }
13264
13265    pub fn context_menu_prev(
13266        &mut self,
13267        _: &ContextMenuPrevious,
13268        window: &mut Window,
13269        cx: &mut Context<Self>,
13270    ) {
13271        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13272            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13273        }
13274    }
13275
13276    pub fn context_menu_next(
13277        &mut self,
13278        _: &ContextMenuNext,
13279        window: &mut Window,
13280        cx: &mut Context<Self>,
13281    ) {
13282        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13283            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13284        }
13285    }
13286
13287    pub fn context_menu_last(
13288        &mut self,
13289        _: &ContextMenuLast,
13290        window: &mut Window,
13291        cx: &mut Context<Self>,
13292    ) {
13293        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13294            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13295        }
13296    }
13297
13298    pub fn signature_help_prev(
13299        &mut self,
13300        _: &SignatureHelpPrevious,
13301        _: &mut Window,
13302        cx: &mut Context<Self>,
13303    ) {
13304        if let Some(popover) = self.signature_help_state.popover_mut() {
13305            if popover.current_signature == 0 {
13306                popover.current_signature = popover.signatures.len() - 1;
13307            } else {
13308                popover.current_signature -= 1;
13309            }
13310            cx.notify();
13311        }
13312    }
13313
13314    pub fn signature_help_next(
13315        &mut self,
13316        _: &SignatureHelpNext,
13317        _: &mut Window,
13318        cx: &mut Context<Self>,
13319    ) {
13320        if let Some(popover) = self.signature_help_state.popover_mut() {
13321            if popover.current_signature + 1 == popover.signatures.len() {
13322                popover.current_signature = 0;
13323            } else {
13324                popover.current_signature += 1;
13325            }
13326            cx.notify();
13327        }
13328    }
13329
13330    pub fn move_to_previous_word_start(
13331        &mut self,
13332        _: &MoveToPreviousWordStart,
13333        window: &mut Window,
13334        cx: &mut Context<Self>,
13335    ) {
13336        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13337        self.change_selections(Default::default(), window, cx, |s| {
13338            s.move_cursors_with(|map, head, _| {
13339                (
13340                    movement::previous_word_start(map, head),
13341                    SelectionGoal::None,
13342                )
13343            });
13344        })
13345    }
13346
13347    pub fn move_to_previous_subword_start(
13348        &mut self,
13349        _: &MoveToPreviousSubwordStart,
13350        window: &mut Window,
13351        cx: &mut Context<Self>,
13352    ) {
13353        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13354        self.change_selections(Default::default(), window, cx, |s| {
13355            s.move_cursors_with(|map, head, _| {
13356                (
13357                    movement::previous_subword_start(map, head),
13358                    SelectionGoal::None,
13359                )
13360            });
13361        })
13362    }
13363
13364    pub fn select_to_previous_word_start(
13365        &mut self,
13366        _: &SelectToPreviousWordStart,
13367        window: &mut Window,
13368        cx: &mut Context<Self>,
13369    ) {
13370        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13371        self.change_selections(Default::default(), window, cx, |s| {
13372            s.move_heads_with(|map, head, _| {
13373                (
13374                    movement::previous_word_start(map, head),
13375                    SelectionGoal::None,
13376                )
13377            });
13378        })
13379    }
13380
13381    pub fn select_to_previous_subword_start(
13382        &mut self,
13383        _: &SelectToPreviousSubwordStart,
13384        window: &mut Window,
13385        cx: &mut Context<Self>,
13386    ) {
13387        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13388        self.change_selections(Default::default(), window, cx, |s| {
13389            s.move_heads_with(|map, head, _| {
13390                (
13391                    movement::previous_subword_start(map, head),
13392                    SelectionGoal::None,
13393                )
13394            });
13395        })
13396    }
13397
13398    pub fn delete_to_previous_word_start(
13399        &mut self,
13400        action: &DeleteToPreviousWordStart,
13401        window: &mut Window,
13402        cx: &mut Context<Self>,
13403    ) {
13404        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13405        self.transact(window, cx, |this, window, cx| {
13406            this.select_autoclose_pair(window, cx);
13407            this.change_selections(Default::default(), window, cx, |s| {
13408                s.move_with(|map, selection| {
13409                    if selection.is_empty() {
13410                        let mut cursor = if action.ignore_newlines {
13411                            movement::previous_word_start(map, selection.head())
13412                        } else {
13413                            movement::previous_word_start_or_newline(map, selection.head())
13414                        };
13415                        cursor = movement::adjust_greedy_deletion(
13416                            map,
13417                            selection.head(),
13418                            cursor,
13419                            action.ignore_brackets,
13420                        );
13421                        selection.set_head(cursor, SelectionGoal::None);
13422                    }
13423                });
13424            });
13425            this.insert("", window, cx);
13426        });
13427    }
13428
13429    pub fn delete_to_previous_subword_start(
13430        &mut self,
13431        _: &DeleteToPreviousSubwordStart,
13432        window: &mut Window,
13433        cx: &mut Context<Self>,
13434    ) {
13435        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13436        self.transact(window, cx, |this, window, cx| {
13437            this.select_autoclose_pair(window, cx);
13438            this.change_selections(Default::default(), window, cx, |s| {
13439                s.move_with(|map, selection| {
13440                    if selection.is_empty() {
13441                        let mut cursor = movement::previous_subword_start(map, selection.head());
13442                        cursor =
13443                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13444                        selection.set_head(cursor, SelectionGoal::None);
13445                    }
13446                });
13447            });
13448            this.insert("", window, cx);
13449        });
13450    }
13451
13452    pub fn move_to_next_word_end(
13453        &mut self,
13454        _: &MoveToNextWordEnd,
13455        window: &mut Window,
13456        cx: &mut Context<Self>,
13457    ) {
13458        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13459        self.change_selections(Default::default(), window, cx, |s| {
13460            s.move_cursors_with(|map, head, _| {
13461                (movement::next_word_end(map, head), SelectionGoal::None)
13462            });
13463        })
13464    }
13465
13466    pub fn move_to_next_subword_end(
13467        &mut self,
13468        _: &MoveToNextSubwordEnd,
13469        window: &mut Window,
13470        cx: &mut Context<Self>,
13471    ) {
13472        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13473        self.change_selections(Default::default(), window, cx, |s| {
13474            s.move_cursors_with(|map, head, _| {
13475                (movement::next_subword_end(map, head), SelectionGoal::None)
13476            });
13477        })
13478    }
13479
13480    pub fn select_to_next_word_end(
13481        &mut self,
13482        _: &SelectToNextWordEnd,
13483        window: &mut Window,
13484        cx: &mut Context<Self>,
13485    ) {
13486        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13487        self.change_selections(Default::default(), window, cx, |s| {
13488            s.move_heads_with(|map, head, _| {
13489                (movement::next_word_end(map, head), SelectionGoal::None)
13490            });
13491        })
13492    }
13493
13494    pub fn select_to_next_subword_end(
13495        &mut self,
13496        _: &SelectToNextSubwordEnd,
13497        window: &mut Window,
13498        cx: &mut Context<Self>,
13499    ) {
13500        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13501        self.change_selections(Default::default(), window, cx, |s| {
13502            s.move_heads_with(|map, head, _| {
13503                (movement::next_subword_end(map, head), SelectionGoal::None)
13504            });
13505        })
13506    }
13507
13508    pub fn delete_to_next_word_end(
13509        &mut self,
13510        action: &DeleteToNextWordEnd,
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 = if action.ignore_newlines {
13520                            movement::next_word_end(map, selection.head())
13521                        } else {
13522                            movement::next_word_end_or_newline(map, selection.head())
13523                        };
13524                        cursor = movement::adjust_greedy_deletion(
13525                            map,
13526                            selection.head(),
13527                            cursor,
13528                            action.ignore_brackets,
13529                        );
13530                        selection.set_head(cursor, SelectionGoal::None);
13531                    }
13532                });
13533            });
13534            this.insert("", window, cx);
13535        });
13536    }
13537
13538    pub fn delete_to_next_subword_end(
13539        &mut self,
13540        _: &DeleteToNextSubwordEnd,
13541        window: &mut Window,
13542        cx: &mut Context<Self>,
13543    ) {
13544        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13545        self.transact(window, cx, |this, window, cx| {
13546            this.change_selections(Default::default(), window, cx, |s| {
13547                s.move_with(|map, selection| {
13548                    if selection.is_empty() {
13549                        let mut cursor = movement::next_subword_end(map, selection.head());
13550                        cursor =
13551                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13552                        selection.set_head(cursor, SelectionGoal::None);
13553                    }
13554                });
13555            });
13556            this.insert("", window, cx);
13557        });
13558    }
13559
13560    pub fn move_to_beginning_of_line(
13561        &mut self,
13562        action: &MoveToBeginningOfLine,
13563        window: &mut Window,
13564        cx: &mut Context<Self>,
13565    ) {
13566        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13567        self.change_selections(Default::default(), window, cx, |s| {
13568            s.move_cursors_with(|map, head, _| {
13569                (
13570                    movement::indented_line_beginning(
13571                        map,
13572                        head,
13573                        action.stop_at_soft_wraps,
13574                        action.stop_at_indent,
13575                    ),
13576                    SelectionGoal::None,
13577                )
13578            });
13579        })
13580    }
13581
13582    pub fn select_to_beginning_of_line(
13583        &mut self,
13584        action: &SelectToBeginningOfLine,
13585        window: &mut Window,
13586        cx: &mut Context<Self>,
13587    ) {
13588        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13589        self.change_selections(Default::default(), window, cx, |s| {
13590            s.move_heads_with(|map, head, _| {
13591                (
13592                    movement::indented_line_beginning(
13593                        map,
13594                        head,
13595                        action.stop_at_soft_wraps,
13596                        action.stop_at_indent,
13597                    ),
13598                    SelectionGoal::None,
13599                )
13600            });
13601        });
13602    }
13603
13604    pub fn delete_to_beginning_of_line(
13605        &mut self,
13606        action: &DeleteToBeginningOfLine,
13607        window: &mut Window,
13608        cx: &mut Context<Self>,
13609    ) {
13610        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13611        self.transact(window, cx, |this, window, cx| {
13612            this.change_selections(Default::default(), window, cx, |s| {
13613                s.move_with(|_, selection| {
13614                    selection.reversed = true;
13615                });
13616            });
13617
13618            this.select_to_beginning_of_line(
13619                &SelectToBeginningOfLine {
13620                    stop_at_soft_wraps: false,
13621                    stop_at_indent: action.stop_at_indent,
13622                },
13623                window,
13624                cx,
13625            );
13626            this.backspace(&Backspace, window, cx);
13627        });
13628    }
13629
13630    pub fn move_to_end_of_line(
13631        &mut self,
13632        action: &MoveToEndOfLine,
13633        window: &mut Window,
13634        cx: &mut Context<Self>,
13635    ) {
13636        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13637        self.change_selections(Default::default(), window, cx, |s| {
13638            s.move_cursors_with(|map, head, _| {
13639                (
13640                    movement::line_end(map, head, action.stop_at_soft_wraps),
13641                    SelectionGoal::None,
13642                )
13643            });
13644        })
13645    }
13646
13647    pub fn select_to_end_of_line(
13648        &mut self,
13649        action: &SelectToEndOfLine,
13650        window: &mut Window,
13651        cx: &mut Context<Self>,
13652    ) {
13653        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13654        self.change_selections(Default::default(), window, cx, |s| {
13655            s.move_heads_with(|map, head, _| {
13656                (
13657                    movement::line_end(map, head, action.stop_at_soft_wraps),
13658                    SelectionGoal::None,
13659                )
13660            });
13661        })
13662    }
13663
13664    pub fn delete_to_end_of_line(
13665        &mut self,
13666        _: &DeleteToEndOfLine,
13667        window: &mut Window,
13668        cx: &mut Context<Self>,
13669    ) {
13670        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13671        self.transact(window, cx, |this, window, cx| {
13672            this.select_to_end_of_line(
13673                &SelectToEndOfLine {
13674                    stop_at_soft_wraps: false,
13675                },
13676                window,
13677                cx,
13678            );
13679            this.delete(&Delete, window, cx);
13680        });
13681    }
13682
13683    pub fn cut_to_end_of_line(
13684        &mut self,
13685        action: &CutToEndOfLine,
13686        window: &mut Window,
13687        cx: &mut Context<Self>,
13688    ) {
13689        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13690        self.transact(window, cx, |this, window, cx| {
13691            this.select_to_end_of_line(
13692                &SelectToEndOfLine {
13693                    stop_at_soft_wraps: false,
13694                },
13695                window,
13696                cx,
13697            );
13698            if !action.stop_at_newlines {
13699                this.change_selections(Default::default(), window, cx, |s| {
13700                    s.move_with(|_, sel| {
13701                        if sel.is_empty() {
13702                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13703                        }
13704                    });
13705                });
13706            }
13707            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13708            let item = this.cut_common(false, window, cx);
13709            cx.write_to_clipboard(item);
13710        });
13711    }
13712
13713    pub fn move_to_start_of_paragraph(
13714        &mut self,
13715        _: &MoveToStartOfParagraph,
13716        window: &mut Window,
13717        cx: &mut Context<Self>,
13718    ) {
13719        if matches!(self.mode, EditorMode::SingleLine) {
13720            cx.propagate();
13721            return;
13722        }
13723        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13724        self.change_selections(Default::default(), window, cx, |s| {
13725            s.move_with(|map, selection| {
13726                selection.collapse_to(
13727                    movement::start_of_paragraph(map, selection.head(), 1),
13728                    SelectionGoal::None,
13729                )
13730            });
13731        })
13732    }
13733
13734    pub fn move_to_end_of_paragraph(
13735        &mut self,
13736        _: &MoveToEndOfParagraph,
13737        window: &mut Window,
13738        cx: &mut Context<Self>,
13739    ) {
13740        if matches!(self.mode, EditorMode::SingleLine) {
13741            cx.propagate();
13742            return;
13743        }
13744        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13745        self.change_selections(Default::default(), window, cx, |s| {
13746            s.move_with(|map, selection| {
13747                selection.collapse_to(
13748                    movement::end_of_paragraph(map, selection.head(), 1),
13749                    SelectionGoal::None,
13750                )
13751            });
13752        })
13753    }
13754
13755    pub fn select_to_start_of_paragraph(
13756        &mut self,
13757        _: &SelectToStartOfParagraph,
13758        window: &mut Window,
13759        cx: &mut Context<Self>,
13760    ) {
13761        if matches!(self.mode, EditorMode::SingleLine) {
13762            cx.propagate();
13763            return;
13764        }
13765        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13766        self.change_selections(Default::default(), window, cx, |s| {
13767            s.move_heads_with(|map, head, _| {
13768                (
13769                    movement::start_of_paragraph(map, head, 1),
13770                    SelectionGoal::None,
13771                )
13772            });
13773        })
13774    }
13775
13776    pub fn select_to_end_of_paragraph(
13777        &mut self,
13778        _: &SelectToEndOfParagraph,
13779        window: &mut Window,
13780        cx: &mut Context<Self>,
13781    ) {
13782        if matches!(self.mode, EditorMode::SingleLine) {
13783            cx.propagate();
13784            return;
13785        }
13786        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13787        self.change_selections(Default::default(), window, cx, |s| {
13788            s.move_heads_with(|map, head, _| {
13789                (
13790                    movement::end_of_paragraph(map, head, 1),
13791                    SelectionGoal::None,
13792                )
13793            });
13794        })
13795    }
13796
13797    pub fn move_to_start_of_excerpt(
13798        &mut self,
13799        _: &MoveToStartOfExcerpt,
13800        window: &mut Window,
13801        cx: &mut Context<Self>,
13802    ) {
13803        if matches!(self.mode, EditorMode::SingleLine) {
13804            cx.propagate();
13805            return;
13806        }
13807        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13808        self.change_selections(Default::default(), window, cx, |s| {
13809            s.move_with(|map, selection| {
13810                selection.collapse_to(
13811                    movement::start_of_excerpt(
13812                        map,
13813                        selection.head(),
13814                        workspace::searchable::Direction::Prev,
13815                    ),
13816                    SelectionGoal::None,
13817                )
13818            });
13819        })
13820    }
13821
13822    pub fn move_to_start_of_next_excerpt(
13823        &mut self,
13824        _: &MoveToStartOfNextExcerpt,
13825        window: &mut Window,
13826        cx: &mut Context<Self>,
13827    ) {
13828        if matches!(self.mode, EditorMode::SingleLine) {
13829            cx.propagate();
13830            return;
13831        }
13832
13833        self.change_selections(Default::default(), window, cx, |s| {
13834            s.move_with(|map, selection| {
13835                selection.collapse_to(
13836                    movement::start_of_excerpt(
13837                        map,
13838                        selection.head(),
13839                        workspace::searchable::Direction::Next,
13840                    ),
13841                    SelectionGoal::None,
13842                )
13843            });
13844        })
13845    }
13846
13847    pub fn move_to_end_of_excerpt(
13848        &mut self,
13849        _: &MoveToEndOfExcerpt,
13850        window: &mut Window,
13851        cx: &mut Context<Self>,
13852    ) {
13853        if matches!(self.mode, EditorMode::SingleLine) {
13854            cx.propagate();
13855            return;
13856        }
13857        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13858        self.change_selections(Default::default(), window, cx, |s| {
13859            s.move_with(|map, selection| {
13860                selection.collapse_to(
13861                    movement::end_of_excerpt(
13862                        map,
13863                        selection.head(),
13864                        workspace::searchable::Direction::Next,
13865                    ),
13866                    SelectionGoal::None,
13867                )
13868            });
13869        })
13870    }
13871
13872    pub fn move_to_end_of_previous_excerpt(
13873        &mut self,
13874        _: &MoveToEndOfPreviousExcerpt,
13875        window: &mut Window,
13876        cx: &mut Context<Self>,
13877    ) {
13878        if matches!(self.mode, EditorMode::SingleLine) {
13879            cx.propagate();
13880            return;
13881        }
13882        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13883        self.change_selections(Default::default(), window, cx, |s| {
13884            s.move_with(|map, selection| {
13885                selection.collapse_to(
13886                    movement::end_of_excerpt(
13887                        map,
13888                        selection.head(),
13889                        workspace::searchable::Direction::Prev,
13890                    ),
13891                    SelectionGoal::None,
13892                )
13893            });
13894        })
13895    }
13896
13897    pub fn select_to_start_of_excerpt(
13898        &mut self,
13899        _: &SelectToStartOfExcerpt,
13900        window: &mut Window,
13901        cx: &mut Context<Self>,
13902    ) {
13903        if matches!(self.mode, EditorMode::SingleLine) {
13904            cx.propagate();
13905            return;
13906        }
13907        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13908        self.change_selections(Default::default(), window, cx, |s| {
13909            s.move_heads_with(|map, head, _| {
13910                (
13911                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13912                    SelectionGoal::None,
13913                )
13914            });
13915        })
13916    }
13917
13918    pub fn select_to_start_of_next_excerpt(
13919        &mut self,
13920        _: &SelectToStartOfNextExcerpt,
13921        window: &mut Window,
13922        cx: &mut Context<Self>,
13923    ) {
13924        if matches!(self.mode, EditorMode::SingleLine) {
13925            cx.propagate();
13926            return;
13927        }
13928        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13929        self.change_selections(Default::default(), window, cx, |s| {
13930            s.move_heads_with(|map, head, _| {
13931                (
13932                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13933                    SelectionGoal::None,
13934                )
13935            });
13936        })
13937    }
13938
13939    pub fn select_to_end_of_excerpt(
13940        &mut self,
13941        _: &SelectToEndOfExcerpt,
13942        window: &mut Window,
13943        cx: &mut Context<Self>,
13944    ) {
13945        if matches!(self.mode, EditorMode::SingleLine) {
13946            cx.propagate();
13947            return;
13948        }
13949        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13950        self.change_selections(Default::default(), window, cx, |s| {
13951            s.move_heads_with(|map, head, _| {
13952                (
13953                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13954                    SelectionGoal::None,
13955                )
13956            });
13957        })
13958    }
13959
13960    pub fn select_to_end_of_previous_excerpt(
13961        &mut self,
13962        _: &SelectToEndOfPreviousExcerpt,
13963        window: &mut Window,
13964        cx: &mut Context<Self>,
13965    ) {
13966        if matches!(self.mode, EditorMode::SingleLine) {
13967            cx.propagate();
13968            return;
13969        }
13970        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13971        self.change_selections(Default::default(), window, cx, |s| {
13972            s.move_heads_with(|map, head, _| {
13973                (
13974                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13975                    SelectionGoal::None,
13976                )
13977            });
13978        })
13979    }
13980
13981    pub fn move_to_beginning(
13982        &mut self,
13983        _: &MoveToBeginning,
13984        window: &mut Window,
13985        cx: &mut Context<Self>,
13986    ) {
13987        if matches!(self.mode, EditorMode::SingleLine) {
13988            cx.propagate();
13989            return;
13990        }
13991        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13992        self.change_selections(Default::default(), window, cx, |s| {
13993            s.select_ranges(vec![0..0]);
13994        });
13995    }
13996
13997    pub fn select_to_beginning(
13998        &mut self,
13999        _: &SelectToBeginning,
14000        window: &mut Window,
14001        cx: &mut Context<Self>,
14002    ) {
14003        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14004        selection.set_head(Point::zero(), SelectionGoal::None);
14005        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14006        self.change_selections(Default::default(), window, cx, |s| {
14007            s.select(vec![selection]);
14008        });
14009    }
14010
14011    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14012        if matches!(self.mode, EditorMode::SingleLine) {
14013            cx.propagate();
14014            return;
14015        }
14016        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14017        let cursor = self.buffer.read(cx).read(cx).len();
14018        self.change_selections(Default::default(), window, cx, |s| {
14019            s.select_ranges(vec![cursor..cursor])
14020        });
14021    }
14022
14023    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14024        self.nav_history = nav_history;
14025    }
14026
14027    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14028        self.nav_history.as_ref()
14029    }
14030
14031    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14032        self.push_to_nav_history(
14033            self.selections.newest_anchor().head(),
14034            None,
14035            false,
14036            true,
14037            cx,
14038        );
14039    }
14040
14041    fn push_to_nav_history(
14042        &mut self,
14043        cursor_anchor: Anchor,
14044        new_position: Option<Point>,
14045        is_deactivate: bool,
14046        always: bool,
14047        cx: &mut Context<Self>,
14048    ) {
14049        if let Some(nav_history) = self.nav_history.as_mut() {
14050            let buffer = self.buffer.read(cx).read(cx);
14051            let cursor_position = cursor_anchor.to_point(&buffer);
14052            let scroll_state = self.scroll_manager.anchor();
14053            let scroll_top_row = scroll_state.top_row(&buffer);
14054            drop(buffer);
14055
14056            if let Some(new_position) = new_position {
14057                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14058                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14059                    return;
14060                }
14061            }
14062
14063            nav_history.push(
14064                Some(NavigationData {
14065                    cursor_anchor,
14066                    cursor_position,
14067                    scroll_anchor: scroll_state,
14068                    scroll_top_row,
14069                }),
14070                cx,
14071            );
14072            cx.emit(EditorEvent::PushedToNavHistory {
14073                anchor: cursor_anchor,
14074                is_deactivate,
14075            })
14076        }
14077    }
14078
14079    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14080        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14081        let buffer = self.buffer.read(cx).snapshot(cx);
14082        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14083        selection.set_head(buffer.len(), SelectionGoal::None);
14084        self.change_selections(Default::default(), window, cx, |s| {
14085            s.select(vec![selection]);
14086        });
14087    }
14088
14089    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14090        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14091        let end = self.buffer.read(cx).read(cx).len();
14092        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14093            s.select_ranges(vec![0..end]);
14094        });
14095    }
14096
14097    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14098        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14099        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14100        let mut selections = self.selections.all::<Point>(&display_map);
14101        let max_point = display_map.buffer_snapshot().max_point();
14102        for selection in &mut selections {
14103            let rows = selection.spanned_rows(true, &display_map);
14104            selection.start = Point::new(rows.start.0, 0);
14105            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14106            selection.reversed = false;
14107        }
14108        self.change_selections(Default::default(), window, cx, |s| {
14109            s.select(selections);
14110        });
14111    }
14112
14113    pub fn split_selection_into_lines(
14114        &mut self,
14115        action: &SplitSelectionIntoLines,
14116        window: &mut Window,
14117        cx: &mut Context<Self>,
14118    ) {
14119        let selections = self
14120            .selections
14121            .all::<Point>(&self.display_snapshot(cx))
14122            .into_iter()
14123            .map(|selection| selection.start..selection.end)
14124            .collect::<Vec<_>>();
14125        self.unfold_ranges(&selections, true, true, cx);
14126
14127        let mut new_selection_ranges = Vec::new();
14128        {
14129            let buffer = self.buffer.read(cx).read(cx);
14130            for selection in selections {
14131                for row in selection.start.row..selection.end.row {
14132                    let line_start = Point::new(row, 0);
14133                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14134
14135                    if action.keep_selections {
14136                        // Keep the selection range for each line
14137                        let selection_start = if row == selection.start.row {
14138                            selection.start
14139                        } else {
14140                            line_start
14141                        };
14142                        new_selection_ranges.push(selection_start..line_end);
14143                    } else {
14144                        // Collapse to cursor at end of line
14145                        new_selection_ranges.push(line_end..line_end);
14146                    }
14147                }
14148
14149                let is_multiline_selection = selection.start.row != selection.end.row;
14150                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14151                // so this action feels more ergonomic when paired with other selection operations
14152                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14153                if !should_skip_last {
14154                    if action.keep_selections {
14155                        if is_multiline_selection {
14156                            let line_start = Point::new(selection.end.row, 0);
14157                            new_selection_ranges.push(line_start..selection.end);
14158                        } else {
14159                            new_selection_ranges.push(selection.start..selection.end);
14160                        }
14161                    } else {
14162                        new_selection_ranges.push(selection.end..selection.end);
14163                    }
14164                }
14165            }
14166        }
14167        self.change_selections(Default::default(), window, cx, |s| {
14168            s.select_ranges(new_selection_ranges);
14169        });
14170    }
14171
14172    pub fn add_selection_above(
14173        &mut self,
14174        action: &AddSelectionAbove,
14175        window: &mut Window,
14176        cx: &mut Context<Self>,
14177    ) {
14178        self.add_selection(true, action.skip_soft_wrap, window, cx);
14179    }
14180
14181    pub fn add_selection_below(
14182        &mut self,
14183        action: &AddSelectionBelow,
14184        window: &mut Window,
14185        cx: &mut Context<Self>,
14186    ) {
14187        self.add_selection(false, action.skip_soft_wrap, window, cx);
14188    }
14189
14190    fn add_selection(
14191        &mut self,
14192        above: bool,
14193        skip_soft_wrap: bool,
14194        window: &mut Window,
14195        cx: &mut Context<Self>,
14196    ) {
14197        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14198
14199        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14200        let all_selections = self.selections.all::<Point>(&display_map);
14201        let text_layout_details = self.text_layout_details(window);
14202
14203        let (mut columnar_selections, new_selections_to_columnarize) = {
14204            if let Some(state) = self.add_selections_state.as_ref() {
14205                let columnar_selection_ids: HashSet<_> = state
14206                    .groups
14207                    .iter()
14208                    .flat_map(|group| group.stack.iter())
14209                    .copied()
14210                    .collect();
14211
14212                all_selections
14213                    .into_iter()
14214                    .partition(|s| columnar_selection_ids.contains(&s.id))
14215            } else {
14216                (Vec::new(), all_selections)
14217            }
14218        };
14219
14220        let mut state = self
14221            .add_selections_state
14222            .take()
14223            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14224
14225        for selection in new_selections_to_columnarize {
14226            let range = selection.display_range(&display_map).sorted();
14227            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14228            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14229            let positions = start_x.min(end_x)..start_x.max(end_x);
14230            let mut stack = Vec::new();
14231            for row in range.start.row().0..=range.end.row().0 {
14232                if let Some(selection) = self.selections.build_columnar_selection(
14233                    &display_map,
14234                    DisplayRow(row),
14235                    &positions,
14236                    selection.reversed,
14237                    &text_layout_details,
14238                ) {
14239                    stack.push(selection.id);
14240                    columnar_selections.push(selection);
14241                }
14242            }
14243            if !stack.is_empty() {
14244                if above {
14245                    stack.reverse();
14246                }
14247                state.groups.push(AddSelectionsGroup { above, stack });
14248            }
14249        }
14250
14251        let mut final_selections = Vec::new();
14252        let end_row = if above {
14253            DisplayRow(0)
14254        } else {
14255            display_map.max_point().row()
14256        };
14257
14258        let mut last_added_item_per_group = HashMap::default();
14259        for group in state.groups.iter_mut() {
14260            if let Some(last_id) = group.stack.last() {
14261                last_added_item_per_group.insert(*last_id, group);
14262            }
14263        }
14264
14265        for selection in columnar_selections {
14266            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14267                if above == group.above {
14268                    let range = selection.display_range(&display_map).sorted();
14269                    debug_assert_eq!(range.start.row(), range.end.row());
14270                    let mut row = range.start.row();
14271                    let positions =
14272                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14273                            Pixels::from(start)..Pixels::from(end)
14274                        } else {
14275                            let start_x =
14276                                display_map.x_for_display_point(range.start, &text_layout_details);
14277                            let end_x =
14278                                display_map.x_for_display_point(range.end, &text_layout_details);
14279                            start_x.min(end_x)..start_x.max(end_x)
14280                        };
14281
14282                    let mut maybe_new_selection = None;
14283                    let direction = if above { -1 } else { 1 };
14284
14285                    while row != end_row {
14286                        if skip_soft_wrap {
14287                            row = display_map
14288                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14289                                .row();
14290                        } else if above {
14291                            row.0 -= 1;
14292                        } else {
14293                            row.0 += 1;
14294                        }
14295
14296                        if let Some(new_selection) = self.selections.build_columnar_selection(
14297                            &display_map,
14298                            row,
14299                            &positions,
14300                            selection.reversed,
14301                            &text_layout_details,
14302                        ) {
14303                            maybe_new_selection = Some(new_selection);
14304                            break;
14305                        }
14306                    }
14307
14308                    if let Some(new_selection) = maybe_new_selection {
14309                        group.stack.push(new_selection.id);
14310                        if above {
14311                            final_selections.push(new_selection);
14312                            final_selections.push(selection);
14313                        } else {
14314                            final_selections.push(selection);
14315                            final_selections.push(new_selection);
14316                        }
14317                    } else {
14318                        final_selections.push(selection);
14319                    }
14320                } else {
14321                    group.stack.pop();
14322                }
14323            } else {
14324                final_selections.push(selection);
14325            }
14326        }
14327
14328        self.change_selections(Default::default(), window, cx, |s| {
14329            s.select(final_selections);
14330        });
14331
14332        let final_selection_ids: HashSet<_> = self
14333            .selections
14334            .all::<Point>(&display_map)
14335            .iter()
14336            .map(|s| s.id)
14337            .collect();
14338        state.groups.retain_mut(|group| {
14339            // selections might get merged above so we remove invalid items from stacks
14340            group.stack.retain(|id| final_selection_ids.contains(id));
14341
14342            // single selection in stack can be treated as initial state
14343            group.stack.len() > 1
14344        });
14345
14346        if !state.groups.is_empty() {
14347            self.add_selections_state = Some(state);
14348        }
14349    }
14350
14351    fn select_match_ranges(
14352        &mut self,
14353        range: Range<usize>,
14354        reversed: bool,
14355        replace_newest: bool,
14356        auto_scroll: Option<Autoscroll>,
14357        window: &mut Window,
14358        cx: &mut Context<Editor>,
14359    ) {
14360        self.unfold_ranges(
14361            std::slice::from_ref(&range),
14362            false,
14363            auto_scroll.is_some(),
14364            cx,
14365        );
14366        let effects = if let Some(scroll) = auto_scroll {
14367            SelectionEffects::scroll(scroll)
14368        } else {
14369            SelectionEffects::no_scroll()
14370        };
14371        self.change_selections(effects, window, cx, |s| {
14372            if replace_newest {
14373                s.delete(s.newest_anchor().id);
14374            }
14375            if reversed {
14376                s.insert_range(range.end..range.start);
14377            } else {
14378                s.insert_range(range);
14379            }
14380        });
14381    }
14382
14383    pub fn select_next_match_internal(
14384        &mut self,
14385        display_map: &DisplaySnapshot,
14386        replace_newest: bool,
14387        autoscroll: Option<Autoscroll>,
14388        window: &mut Window,
14389        cx: &mut Context<Self>,
14390    ) -> Result<()> {
14391        let buffer = display_map.buffer_snapshot();
14392        let mut selections = self.selections.all::<usize>(&display_map);
14393        if let Some(mut select_next_state) = self.select_next_state.take() {
14394            let query = &select_next_state.query;
14395            if !select_next_state.done {
14396                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14397                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14398                let mut next_selected_range = None;
14399
14400                let bytes_after_last_selection =
14401                    buffer.bytes_in_range(last_selection.end..buffer.len());
14402                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14403                let query_matches = query
14404                    .stream_find_iter(bytes_after_last_selection)
14405                    .map(|result| (last_selection.end, result))
14406                    .chain(
14407                        query
14408                            .stream_find_iter(bytes_before_first_selection)
14409                            .map(|result| (0, result)),
14410                    );
14411
14412                for (start_offset, query_match) in query_matches {
14413                    let query_match = query_match.unwrap(); // can only fail due to I/O
14414                    let offset_range =
14415                        start_offset + query_match.start()..start_offset + query_match.end();
14416
14417                    if !select_next_state.wordwise
14418                        || (!buffer.is_inside_word(offset_range.start, None)
14419                            && !buffer.is_inside_word(offset_range.end, None))
14420                    {
14421                        let idx = selections
14422                            .partition_point(|selection| selection.end <= offset_range.start);
14423                        let overlaps = selections
14424                            .get(idx)
14425                            .map_or(false, |selection| selection.start < offset_range.end);
14426
14427                        if !overlaps {
14428                            next_selected_range = Some(offset_range);
14429                            break;
14430                        }
14431                    }
14432                }
14433
14434                if let Some(next_selected_range) = next_selected_range {
14435                    self.select_match_ranges(
14436                        next_selected_range,
14437                        last_selection.reversed,
14438                        replace_newest,
14439                        autoscroll,
14440                        window,
14441                        cx,
14442                    );
14443                } else {
14444                    select_next_state.done = true;
14445                }
14446            }
14447
14448            self.select_next_state = Some(select_next_state);
14449        } else {
14450            let mut only_carets = true;
14451            let mut same_text_selected = true;
14452            let mut selected_text = None;
14453
14454            let mut selections_iter = selections.iter().peekable();
14455            while let Some(selection) = selections_iter.next() {
14456                if selection.start != selection.end {
14457                    only_carets = false;
14458                }
14459
14460                if same_text_selected {
14461                    if selected_text.is_none() {
14462                        selected_text =
14463                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14464                    }
14465
14466                    if let Some(next_selection) = selections_iter.peek() {
14467                        if next_selection.range().len() == selection.range().len() {
14468                            let next_selected_text = buffer
14469                                .text_for_range(next_selection.range())
14470                                .collect::<String>();
14471                            if Some(next_selected_text) != selected_text {
14472                                same_text_selected = false;
14473                                selected_text = None;
14474                            }
14475                        } else {
14476                            same_text_selected = false;
14477                            selected_text = None;
14478                        }
14479                    }
14480                }
14481            }
14482
14483            if only_carets {
14484                for selection in &mut selections {
14485                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14486                    selection.start = word_range.start;
14487                    selection.end = word_range.end;
14488                    selection.goal = SelectionGoal::None;
14489                    selection.reversed = false;
14490                    self.select_match_ranges(
14491                        selection.start..selection.end,
14492                        selection.reversed,
14493                        replace_newest,
14494                        autoscroll,
14495                        window,
14496                        cx,
14497                    );
14498                }
14499
14500                if selections.len() == 1 {
14501                    let selection = selections
14502                        .last()
14503                        .expect("ensured that there's only one selection");
14504                    let query = buffer
14505                        .text_for_range(selection.start..selection.end)
14506                        .collect::<String>();
14507                    let is_empty = query.is_empty();
14508                    let select_state = SelectNextState {
14509                        query: AhoCorasick::new(&[query])?,
14510                        wordwise: true,
14511                        done: is_empty,
14512                    };
14513                    self.select_next_state = Some(select_state);
14514                } else {
14515                    self.select_next_state = None;
14516                }
14517            } else if let Some(selected_text) = selected_text {
14518                self.select_next_state = Some(SelectNextState {
14519                    query: AhoCorasick::new(&[selected_text])?,
14520                    wordwise: false,
14521                    done: false,
14522                });
14523                self.select_next_match_internal(
14524                    display_map,
14525                    replace_newest,
14526                    autoscroll,
14527                    window,
14528                    cx,
14529                )?;
14530            }
14531        }
14532        Ok(())
14533    }
14534
14535    pub fn select_all_matches(
14536        &mut self,
14537        _action: &SelectAllMatches,
14538        window: &mut Window,
14539        cx: &mut Context<Self>,
14540    ) -> Result<()> {
14541        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14542
14543        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14544
14545        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14546        let Some(select_next_state) = self.select_next_state.as_mut() else {
14547            return Ok(());
14548        };
14549        if select_next_state.done {
14550            return Ok(());
14551        }
14552
14553        let mut new_selections = Vec::new();
14554
14555        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14556        let buffer = display_map.buffer_snapshot();
14557        let query_matches = select_next_state
14558            .query
14559            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14560
14561        for query_match in query_matches.into_iter() {
14562            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14563            let offset_range = if reversed {
14564                query_match.end()..query_match.start()
14565            } else {
14566                query_match.start()..query_match.end()
14567            };
14568
14569            if !select_next_state.wordwise
14570                || (!buffer.is_inside_word(offset_range.start, None)
14571                    && !buffer.is_inside_word(offset_range.end, None))
14572            {
14573                new_selections.push(offset_range.start..offset_range.end);
14574            }
14575        }
14576
14577        select_next_state.done = true;
14578
14579        if new_selections.is_empty() {
14580            log::error!("bug: new_selections is empty in select_all_matches");
14581            return Ok(());
14582        }
14583
14584        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14585        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14586            selections.select_ranges(new_selections)
14587        });
14588
14589        Ok(())
14590    }
14591
14592    pub fn select_next(
14593        &mut self,
14594        action: &SelectNext,
14595        window: &mut Window,
14596        cx: &mut Context<Self>,
14597    ) -> Result<()> {
14598        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14599        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14600        self.select_next_match_internal(
14601            &display_map,
14602            action.replace_newest,
14603            Some(Autoscroll::newest()),
14604            window,
14605            cx,
14606        )?;
14607        Ok(())
14608    }
14609
14610    pub fn select_previous(
14611        &mut self,
14612        action: &SelectPrevious,
14613        window: &mut Window,
14614        cx: &mut Context<Self>,
14615    ) -> Result<()> {
14616        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14617        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14618        let buffer = display_map.buffer_snapshot();
14619        let mut selections = self.selections.all::<usize>(&display_map);
14620        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14621            let query = &select_prev_state.query;
14622            if !select_prev_state.done {
14623                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14624                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14625                let mut next_selected_range = None;
14626                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14627                let bytes_before_last_selection =
14628                    buffer.reversed_bytes_in_range(0..last_selection.start);
14629                let bytes_after_first_selection =
14630                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14631                let query_matches = query
14632                    .stream_find_iter(bytes_before_last_selection)
14633                    .map(|result| (last_selection.start, result))
14634                    .chain(
14635                        query
14636                            .stream_find_iter(bytes_after_first_selection)
14637                            .map(|result| (buffer.len(), result)),
14638                    );
14639                for (end_offset, query_match) in query_matches {
14640                    let query_match = query_match.unwrap(); // can only fail due to I/O
14641                    let offset_range =
14642                        end_offset - query_match.end()..end_offset - query_match.start();
14643
14644                    if !select_prev_state.wordwise
14645                        || (!buffer.is_inside_word(offset_range.start, None)
14646                            && !buffer.is_inside_word(offset_range.end, None))
14647                    {
14648                        next_selected_range = Some(offset_range);
14649                        break;
14650                    }
14651                }
14652
14653                if let Some(next_selected_range) = next_selected_range {
14654                    self.select_match_ranges(
14655                        next_selected_range,
14656                        last_selection.reversed,
14657                        action.replace_newest,
14658                        Some(Autoscroll::newest()),
14659                        window,
14660                        cx,
14661                    );
14662                } else {
14663                    select_prev_state.done = true;
14664                }
14665            }
14666
14667            self.select_prev_state = Some(select_prev_state);
14668        } else {
14669            let mut only_carets = true;
14670            let mut same_text_selected = true;
14671            let mut selected_text = None;
14672
14673            let mut selections_iter = selections.iter().peekable();
14674            while let Some(selection) = selections_iter.next() {
14675                if selection.start != selection.end {
14676                    only_carets = false;
14677                }
14678
14679                if same_text_selected {
14680                    if selected_text.is_none() {
14681                        selected_text =
14682                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14683                    }
14684
14685                    if let Some(next_selection) = selections_iter.peek() {
14686                        if next_selection.range().len() == selection.range().len() {
14687                            let next_selected_text = buffer
14688                                .text_for_range(next_selection.range())
14689                                .collect::<String>();
14690                            if Some(next_selected_text) != selected_text {
14691                                same_text_selected = false;
14692                                selected_text = None;
14693                            }
14694                        } else {
14695                            same_text_selected = false;
14696                            selected_text = None;
14697                        }
14698                    }
14699                }
14700            }
14701
14702            if only_carets {
14703                for selection in &mut selections {
14704                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14705                    selection.start = word_range.start;
14706                    selection.end = word_range.end;
14707                    selection.goal = SelectionGoal::None;
14708                    selection.reversed = false;
14709                    self.select_match_ranges(
14710                        selection.start..selection.end,
14711                        selection.reversed,
14712                        action.replace_newest,
14713                        Some(Autoscroll::newest()),
14714                        window,
14715                        cx,
14716                    );
14717                }
14718                if selections.len() == 1 {
14719                    let selection = selections
14720                        .last()
14721                        .expect("ensured that there's only one selection");
14722                    let query = buffer
14723                        .text_for_range(selection.start..selection.end)
14724                        .collect::<String>();
14725                    let is_empty = query.is_empty();
14726                    let select_state = SelectNextState {
14727                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14728                        wordwise: true,
14729                        done: is_empty,
14730                    };
14731                    self.select_prev_state = Some(select_state);
14732                } else {
14733                    self.select_prev_state = None;
14734                }
14735            } else if let Some(selected_text) = selected_text {
14736                self.select_prev_state = Some(SelectNextState {
14737                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14738                    wordwise: false,
14739                    done: false,
14740                });
14741                self.select_previous(action, window, cx)?;
14742            }
14743        }
14744        Ok(())
14745    }
14746
14747    pub fn find_next_match(
14748        &mut self,
14749        _: &FindNextMatch,
14750        window: &mut Window,
14751        cx: &mut Context<Self>,
14752    ) -> Result<()> {
14753        let selections = self.selections.disjoint_anchors_arc();
14754        match selections.first() {
14755            Some(first) if selections.len() >= 2 => {
14756                self.change_selections(Default::default(), window, cx, |s| {
14757                    s.select_ranges([first.range()]);
14758                });
14759            }
14760            _ => self.select_next(
14761                &SelectNext {
14762                    replace_newest: true,
14763                },
14764                window,
14765                cx,
14766            )?,
14767        }
14768        Ok(())
14769    }
14770
14771    pub fn find_previous_match(
14772        &mut self,
14773        _: &FindPreviousMatch,
14774        window: &mut Window,
14775        cx: &mut Context<Self>,
14776    ) -> Result<()> {
14777        let selections = self.selections.disjoint_anchors_arc();
14778        match selections.last() {
14779            Some(last) if selections.len() >= 2 => {
14780                self.change_selections(Default::default(), window, cx, |s| {
14781                    s.select_ranges([last.range()]);
14782                });
14783            }
14784            _ => self.select_previous(
14785                &SelectPrevious {
14786                    replace_newest: true,
14787                },
14788                window,
14789                cx,
14790            )?,
14791        }
14792        Ok(())
14793    }
14794
14795    pub fn toggle_comments(
14796        &mut self,
14797        action: &ToggleComments,
14798        window: &mut Window,
14799        cx: &mut Context<Self>,
14800    ) {
14801        if self.read_only(cx) {
14802            return;
14803        }
14804        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14805        let text_layout_details = &self.text_layout_details(window);
14806        self.transact(window, cx, |this, window, cx| {
14807            let mut selections = this
14808                .selections
14809                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14810            let mut edits = Vec::new();
14811            let mut selection_edit_ranges = Vec::new();
14812            let mut last_toggled_row = None;
14813            let snapshot = this.buffer.read(cx).read(cx);
14814            let empty_str: Arc<str> = Arc::default();
14815            let mut suffixes_inserted = Vec::new();
14816            let ignore_indent = action.ignore_indent;
14817
14818            fn comment_prefix_range(
14819                snapshot: &MultiBufferSnapshot,
14820                row: MultiBufferRow,
14821                comment_prefix: &str,
14822                comment_prefix_whitespace: &str,
14823                ignore_indent: bool,
14824            ) -> Range<Point> {
14825                let indent_size = if ignore_indent {
14826                    0
14827                } else {
14828                    snapshot.indent_size_for_line(row).len
14829                };
14830
14831                let start = Point::new(row.0, indent_size);
14832
14833                let mut line_bytes = snapshot
14834                    .bytes_in_range(start..snapshot.max_point())
14835                    .flatten()
14836                    .copied();
14837
14838                // If this line currently begins with the line comment prefix, then record
14839                // the range containing the prefix.
14840                if line_bytes
14841                    .by_ref()
14842                    .take(comment_prefix.len())
14843                    .eq(comment_prefix.bytes())
14844                {
14845                    // Include any whitespace that matches the comment prefix.
14846                    let matching_whitespace_len = line_bytes
14847                        .zip(comment_prefix_whitespace.bytes())
14848                        .take_while(|(a, b)| a == b)
14849                        .count() as u32;
14850                    let end = Point::new(
14851                        start.row,
14852                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14853                    );
14854                    start..end
14855                } else {
14856                    start..start
14857                }
14858            }
14859
14860            fn comment_suffix_range(
14861                snapshot: &MultiBufferSnapshot,
14862                row: MultiBufferRow,
14863                comment_suffix: &str,
14864                comment_suffix_has_leading_space: bool,
14865            ) -> Range<Point> {
14866                let end = Point::new(row.0, snapshot.line_len(row));
14867                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14868
14869                let mut line_end_bytes = snapshot
14870                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14871                    .flatten()
14872                    .copied();
14873
14874                let leading_space_len = if suffix_start_column > 0
14875                    && line_end_bytes.next() == Some(b' ')
14876                    && comment_suffix_has_leading_space
14877                {
14878                    1
14879                } else {
14880                    0
14881                };
14882
14883                // If this line currently begins with the line comment prefix, then record
14884                // the range containing the prefix.
14885                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14886                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14887                    start..end
14888                } else {
14889                    end..end
14890                }
14891            }
14892
14893            // TODO: Handle selections that cross excerpts
14894            for selection in &mut selections {
14895                let start_column = snapshot
14896                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14897                    .len;
14898                let language = if let Some(language) =
14899                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14900                {
14901                    language
14902                } else {
14903                    continue;
14904                };
14905
14906                selection_edit_ranges.clear();
14907
14908                // If multiple selections contain a given row, avoid processing that
14909                // row more than once.
14910                let mut start_row = MultiBufferRow(selection.start.row);
14911                if last_toggled_row == Some(start_row) {
14912                    start_row = start_row.next_row();
14913                }
14914                let end_row =
14915                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14916                        MultiBufferRow(selection.end.row - 1)
14917                    } else {
14918                        MultiBufferRow(selection.end.row)
14919                    };
14920                last_toggled_row = Some(end_row);
14921
14922                if start_row > end_row {
14923                    continue;
14924                }
14925
14926                // If the language has line comments, toggle those.
14927                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14928
14929                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14930                if ignore_indent {
14931                    full_comment_prefixes = full_comment_prefixes
14932                        .into_iter()
14933                        .map(|s| Arc::from(s.trim_end()))
14934                        .collect();
14935                }
14936
14937                if !full_comment_prefixes.is_empty() {
14938                    let first_prefix = full_comment_prefixes
14939                        .first()
14940                        .expect("prefixes is non-empty");
14941                    let prefix_trimmed_lengths = full_comment_prefixes
14942                        .iter()
14943                        .map(|p| p.trim_end_matches(' ').len())
14944                        .collect::<SmallVec<[usize; 4]>>();
14945
14946                    let mut all_selection_lines_are_comments = true;
14947
14948                    for row in start_row.0..=end_row.0 {
14949                        let row = MultiBufferRow(row);
14950                        if start_row < end_row && snapshot.is_line_blank(row) {
14951                            continue;
14952                        }
14953
14954                        let prefix_range = full_comment_prefixes
14955                            .iter()
14956                            .zip(prefix_trimmed_lengths.iter().copied())
14957                            .map(|(prefix, trimmed_prefix_len)| {
14958                                comment_prefix_range(
14959                                    snapshot.deref(),
14960                                    row,
14961                                    &prefix[..trimmed_prefix_len],
14962                                    &prefix[trimmed_prefix_len..],
14963                                    ignore_indent,
14964                                )
14965                            })
14966                            .max_by_key(|range| range.end.column - range.start.column)
14967                            .expect("prefixes is non-empty");
14968
14969                        if prefix_range.is_empty() {
14970                            all_selection_lines_are_comments = false;
14971                        }
14972
14973                        selection_edit_ranges.push(prefix_range);
14974                    }
14975
14976                    if all_selection_lines_are_comments {
14977                        edits.extend(
14978                            selection_edit_ranges
14979                                .iter()
14980                                .cloned()
14981                                .map(|range| (range, empty_str.clone())),
14982                        );
14983                    } else {
14984                        let min_column = selection_edit_ranges
14985                            .iter()
14986                            .map(|range| range.start.column)
14987                            .min()
14988                            .unwrap_or(0);
14989                        edits.extend(selection_edit_ranges.iter().map(|range| {
14990                            let position = Point::new(range.start.row, min_column);
14991                            (position..position, first_prefix.clone())
14992                        }));
14993                    }
14994                } else if let Some(BlockCommentConfig {
14995                    start: full_comment_prefix,
14996                    end: comment_suffix,
14997                    ..
14998                }) = language.block_comment()
14999                {
15000                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15001                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15002                    let prefix_range = comment_prefix_range(
15003                        snapshot.deref(),
15004                        start_row,
15005                        comment_prefix,
15006                        comment_prefix_whitespace,
15007                        ignore_indent,
15008                    );
15009                    let suffix_range = comment_suffix_range(
15010                        snapshot.deref(),
15011                        end_row,
15012                        comment_suffix.trim_start_matches(' '),
15013                        comment_suffix.starts_with(' '),
15014                    );
15015
15016                    if prefix_range.is_empty() || suffix_range.is_empty() {
15017                        edits.push((
15018                            prefix_range.start..prefix_range.start,
15019                            full_comment_prefix.clone(),
15020                        ));
15021                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15022                        suffixes_inserted.push((end_row, comment_suffix.len()));
15023                    } else {
15024                        edits.push((prefix_range, empty_str.clone()));
15025                        edits.push((suffix_range, empty_str.clone()));
15026                    }
15027                } else {
15028                    continue;
15029                }
15030            }
15031
15032            drop(snapshot);
15033            this.buffer.update(cx, |buffer, cx| {
15034                buffer.edit(edits, None, cx);
15035            });
15036
15037            // Adjust selections so that they end before any comment suffixes that
15038            // were inserted.
15039            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15040            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15041            let snapshot = this.buffer.read(cx).read(cx);
15042            for selection in &mut selections {
15043                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15044                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15045                        Ordering::Less => {
15046                            suffixes_inserted.next();
15047                            continue;
15048                        }
15049                        Ordering::Greater => break,
15050                        Ordering::Equal => {
15051                            if selection.end.column == snapshot.line_len(row) {
15052                                if selection.is_empty() {
15053                                    selection.start.column -= suffix_len as u32;
15054                                }
15055                                selection.end.column -= suffix_len as u32;
15056                            }
15057                            break;
15058                        }
15059                    }
15060                }
15061            }
15062
15063            drop(snapshot);
15064            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15065
15066            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15067            let selections_on_single_row = selections.windows(2).all(|selections| {
15068                selections[0].start.row == selections[1].start.row
15069                    && selections[0].end.row == selections[1].end.row
15070                    && selections[0].start.row == selections[0].end.row
15071            });
15072            let selections_selecting = selections
15073                .iter()
15074                .any(|selection| selection.start != selection.end);
15075            let advance_downwards = action.advance_downwards
15076                && selections_on_single_row
15077                && !selections_selecting
15078                && !matches!(this.mode, EditorMode::SingleLine);
15079
15080            if advance_downwards {
15081                let snapshot = this.buffer.read(cx).snapshot(cx);
15082
15083                this.change_selections(Default::default(), window, cx, |s| {
15084                    s.move_cursors_with(|display_snapshot, display_point, _| {
15085                        let mut point = display_point.to_point(display_snapshot);
15086                        point.row += 1;
15087                        point = snapshot.clip_point(point, Bias::Left);
15088                        let display_point = point.to_display_point(display_snapshot);
15089                        let goal = SelectionGoal::HorizontalPosition(
15090                            display_snapshot
15091                                .x_for_display_point(display_point, text_layout_details)
15092                                .into(),
15093                        );
15094                        (display_point, goal)
15095                    })
15096                });
15097            }
15098        });
15099    }
15100
15101    pub fn select_enclosing_symbol(
15102        &mut self,
15103        _: &SelectEnclosingSymbol,
15104        window: &mut Window,
15105        cx: &mut Context<Self>,
15106    ) {
15107        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15108
15109        let buffer = self.buffer.read(cx).snapshot(cx);
15110        let old_selections = self
15111            .selections
15112            .all::<usize>(&self.display_snapshot(cx))
15113            .into_boxed_slice();
15114
15115        fn update_selection(
15116            selection: &Selection<usize>,
15117            buffer_snap: &MultiBufferSnapshot,
15118        ) -> Option<Selection<usize>> {
15119            let cursor = selection.head();
15120            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15121            for symbol in symbols.iter().rev() {
15122                let start = symbol.range.start.to_offset(buffer_snap);
15123                let end = symbol.range.end.to_offset(buffer_snap);
15124                let new_range = start..end;
15125                if start < selection.start || end > selection.end {
15126                    return Some(Selection {
15127                        id: selection.id,
15128                        start: new_range.start,
15129                        end: new_range.end,
15130                        goal: SelectionGoal::None,
15131                        reversed: selection.reversed,
15132                    });
15133                }
15134            }
15135            None
15136        }
15137
15138        let mut selected_larger_symbol = false;
15139        let new_selections = old_selections
15140            .iter()
15141            .map(|selection| match update_selection(selection, &buffer) {
15142                Some(new_selection) => {
15143                    if new_selection.range() != selection.range() {
15144                        selected_larger_symbol = true;
15145                    }
15146                    new_selection
15147                }
15148                None => selection.clone(),
15149            })
15150            .collect::<Vec<_>>();
15151
15152        if selected_larger_symbol {
15153            self.change_selections(Default::default(), window, cx, |s| {
15154                s.select(new_selections);
15155            });
15156        }
15157    }
15158
15159    pub fn select_larger_syntax_node(
15160        &mut self,
15161        _: &SelectLargerSyntaxNode,
15162        window: &mut Window,
15163        cx: &mut Context<Self>,
15164    ) {
15165        let Some(visible_row_count) = self.visible_row_count() else {
15166            return;
15167        };
15168        let old_selections: Box<[_]> = self
15169            .selections
15170            .all::<usize>(&self.display_snapshot(cx))
15171            .into();
15172        if old_selections.is_empty() {
15173            return;
15174        }
15175
15176        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15177
15178        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15179        let buffer = self.buffer.read(cx).snapshot(cx);
15180
15181        let mut selected_larger_node = false;
15182        let mut new_selections = old_selections
15183            .iter()
15184            .map(|selection| {
15185                let old_range = selection.start..selection.end;
15186
15187                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15188                    // manually select word at selection
15189                    if ["string_content", "inline"].contains(&node.kind()) {
15190                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15191                        // ignore if word is already selected
15192                        if !word_range.is_empty() && old_range != word_range {
15193                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15194                            // only select word if start and end point belongs to same word
15195                            if word_range == last_word_range {
15196                                selected_larger_node = true;
15197                                return Selection {
15198                                    id: selection.id,
15199                                    start: word_range.start,
15200                                    end: word_range.end,
15201                                    goal: SelectionGoal::None,
15202                                    reversed: selection.reversed,
15203                                };
15204                            }
15205                        }
15206                    }
15207                }
15208
15209                let mut new_range = old_range.clone();
15210                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15211                    new_range = range;
15212                    if !node.is_named() {
15213                        continue;
15214                    }
15215                    if !display_map.intersects_fold(new_range.start)
15216                        && !display_map.intersects_fold(new_range.end)
15217                    {
15218                        break;
15219                    }
15220                }
15221
15222                selected_larger_node |= new_range != old_range;
15223                Selection {
15224                    id: selection.id,
15225                    start: new_range.start,
15226                    end: new_range.end,
15227                    goal: SelectionGoal::None,
15228                    reversed: selection.reversed,
15229                }
15230            })
15231            .collect::<Vec<_>>();
15232
15233        if !selected_larger_node {
15234            return; // don't put this call in the history
15235        }
15236
15237        // scroll based on transformation done to the last selection created by the user
15238        let (last_old, last_new) = old_selections
15239            .last()
15240            .zip(new_selections.last().cloned())
15241            .expect("old_selections isn't empty");
15242
15243        // revert selection
15244        let is_selection_reversed = {
15245            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15246            new_selections.last_mut().expect("checked above").reversed =
15247                should_newest_selection_be_reversed;
15248            should_newest_selection_be_reversed
15249        };
15250
15251        if selected_larger_node {
15252            self.select_syntax_node_history.disable_clearing = true;
15253            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15254                s.select(new_selections.clone());
15255            });
15256            self.select_syntax_node_history.disable_clearing = false;
15257        }
15258
15259        let start_row = last_new.start.to_display_point(&display_map).row().0;
15260        let end_row = last_new.end.to_display_point(&display_map).row().0;
15261        let selection_height = end_row - start_row + 1;
15262        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15263
15264        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15265        let scroll_behavior = if fits_on_the_screen {
15266            self.request_autoscroll(Autoscroll::fit(), cx);
15267            SelectSyntaxNodeScrollBehavior::FitSelection
15268        } else if is_selection_reversed {
15269            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15270            SelectSyntaxNodeScrollBehavior::CursorTop
15271        } else {
15272            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15273            SelectSyntaxNodeScrollBehavior::CursorBottom
15274        };
15275
15276        self.select_syntax_node_history.push((
15277            old_selections,
15278            scroll_behavior,
15279            is_selection_reversed,
15280        ));
15281    }
15282
15283    pub fn select_smaller_syntax_node(
15284        &mut self,
15285        _: &SelectSmallerSyntaxNode,
15286        window: &mut Window,
15287        cx: &mut Context<Self>,
15288    ) {
15289        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15290
15291        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15292            self.select_syntax_node_history.pop()
15293        {
15294            if let Some(selection) = selections.last_mut() {
15295                selection.reversed = is_selection_reversed;
15296            }
15297
15298            self.select_syntax_node_history.disable_clearing = true;
15299            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15300                s.select(selections.to_vec());
15301            });
15302            self.select_syntax_node_history.disable_clearing = false;
15303
15304            match scroll_behavior {
15305                SelectSyntaxNodeScrollBehavior::CursorTop => {
15306                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15307                }
15308                SelectSyntaxNodeScrollBehavior::FitSelection => {
15309                    self.request_autoscroll(Autoscroll::fit(), cx);
15310                }
15311                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15312                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15313                }
15314            }
15315        }
15316    }
15317
15318    pub fn unwrap_syntax_node(
15319        &mut self,
15320        _: &UnwrapSyntaxNode,
15321        window: &mut Window,
15322        cx: &mut Context<Self>,
15323    ) {
15324        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15325
15326        let buffer = self.buffer.read(cx).snapshot(cx);
15327        let selections = self
15328            .selections
15329            .all::<usize>(&self.display_snapshot(cx))
15330            .into_iter()
15331            // subtracting the offset requires sorting
15332            .sorted_by_key(|i| i.start);
15333
15334        let full_edits = selections
15335            .into_iter()
15336            .filter_map(|selection| {
15337                let child = if selection.is_empty()
15338                    && let Some((_, ancestor_range)) =
15339                        buffer.syntax_ancestor(selection.start..selection.end)
15340                {
15341                    ancestor_range
15342                } else {
15343                    selection.range()
15344                };
15345
15346                let mut parent = child.clone();
15347                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15348                    parent = ancestor_range;
15349                    if parent.start < child.start || parent.end > child.end {
15350                        break;
15351                    }
15352                }
15353
15354                if parent == child {
15355                    return None;
15356                }
15357                let text = buffer.text_for_range(child).collect::<String>();
15358                Some((selection.id, parent, text))
15359            })
15360            .collect::<Vec<_>>();
15361        if full_edits.is_empty() {
15362            return;
15363        }
15364
15365        self.transact(window, cx, |this, window, cx| {
15366            this.buffer.update(cx, |buffer, cx| {
15367                buffer.edit(
15368                    full_edits
15369                        .iter()
15370                        .map(|(_, p, t)| (p.clone(), t.clone()))
15371                        .collect::<Vec<_>>(),
15372                    None,
15373                    cx,
15374                );
15375            });
15376            this.change_selections(Default::default(), window, cx, |s| {
15377                let mut offset = 0;
15378                let mut selections = vec![];
15379                for (id, parent, text) in full_edits {
15380                    let start = parent.start - offset;
15381                    offset += parent.len() - text.len();
15382                    selections.push(Selection {
15383                        id,
15384                        start,
15385                        end: start + text.len(),
15386                        reversed: false,
15387                        goal: Default::default(),
15388                    });
15389                }
15390                s.select(selections);
15391            });
15392        });
15393    }
15394
15395    pub fn select_next_syntax_node(
15396        &mut self,
15397        _: &SelectNextSyntaxNode,
15398        window: &mut Window,
15399        cx: &mut Context<Self>,
15400    ) {
15401        let old_selections: Box<[_]> = self
15402            .selections
15403            .all::<usize>(&self.display_snapshot(cx))
15404            .into();
15405        if old_selections.is_empty() {
15406            return;
15407        }
15408
15409        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15410
15411        let buffer = self.buffer.read(cx).snapshot(cx);
15412        let mut selected_sibling = false;
15413
15414        let new_selections = old_selections
15415            .iter()
15416            .map(|selection| {
15417                let old_range = selection.start..selection.end;
15418
15419                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15420                    let new_range = node.byte_range();
15421                    selected_sibling = true;
15422                    Selection {
15423                        id: selection.id,
15424                        start: new_range.start,
15425                        end: new_range.end,
15426                        goal: SelectionGoal::None,
15427                        reversed: selection.reversed,
15428                    }
15429                } else {
15430                    selection.clone()
15431                }
15432            })
15433            .collect::<Vec<_>>();
15434
15435        if selected_sibling {
15436            self.change_selections(
15437                SelectionEffects::scroll(Autoscroll::fit()),
15438                window,
15439                cx,
15440                |s| {
15441                    s.select(new_selections);
15442                },
15443            );
15444        }
15445    }
15446
15447    pub fn select_prev_syntax_node(
15448        &mut self,
15449        _: &SelectPreviousSyntaxNode,
15450        window: &mut Window,
15451        cx: &mut Context<Self>,
15452    ) {
15453        let old_selections: Box<[_]> = self
15454            .selections
15455            .all::<usize>(&self.display_snapshot(cx))
15456            .into();
15457        if old_selections.is_empty() {
15458            return;
15459        }
15460
15461        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15462
15463        let buffer = self.buffer.read(cx).snapshot(cx);
15464        let mut selected_sibling = false;
15465
15466        let new_selections = old_selections
15467            .iter()
15468            .map(|selection| {
15469                let old_range = selection.start..selection.end;
15470
15471                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15472                    let new_range = node.byte_range();
15473                    selected_sibling = true;
15474                    Selection {
15475                        id: selection.id,
15476                        start: new_range.start,
15477                        end: new_range.end,
15478                        goal: SelectionGoal::None,
15479                        reversed: selection.reversed,
15480                    }
15481                } else {
15482                    selection.clone()
15483                }
15484            })
15485            .collect::<Vec<_>>();
15486
15487        if selected_sibling {
15488            self.change_selections(
15489                SelectionEffects::scroll(Autoscroll::fit()),
15490                window,
15491                cx,
15492                |s| {
15493                    s.select(new_selections);
15494                },
15495            );
15496        }
15497    }
15498
15499    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15500        if !EditorSettings::get_global(cx).gutter.runnables {
15501            self.clear_tasks();
15502            return Task::ready(());
15503        }
15504        let project = self.project().map(Entity::downgrade);
15505        let task_sources = self.lsp_task_sources(cx);
15506        let multi_buffer = self.buffer.downgrade();
15507        cx.spawn_in(window, async move |editor, cx| {
15508            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15509            let Some(project) = project.and_then(|p| p.upgrade()) else {
15510                return;
15511            };
15512            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15513                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15514            }) else {
15515                return;
15516            };
15517
15518            let hide_runnables = project
15519                .update(cx, |project, _| project.is_via_collab())
15520                .unwrap_or(true);
15521            if hide_runnables {
15522                return;
15523            }
15524            let new_rows =
15525                cx.background_spawn({
15526                    let snapshot = display_snapshot.clone();
15527                    async move {
15528                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15529                    }
15530                })
15531                    .await;
15532            let Ok(lsp_tasks) =
15533                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15534            else {
15535                return;
15536            };
15537            let lsp_tasks = lsp_tasks.await;
15538
15539            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15540                lsp_tasks
15541                    .into_iter()
15542                    .flat_map(|(kind, tasks)| {
15543                        tasks.into_iter().filter_map(move |(location, task)| {
15544                            Some((kind.clone(), location?, task))
15545                        })
15546                    })
15547                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15548                        let buffer = location.target.buffer;
15549                        let buffer_snapshot = buffer.read(cx).snapshot();
15550                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15551                            |(excerpt_id, snapshot, _)| {
15552                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15553                                    display_snapshot
15554                                        .buffer_snapshot()
15555                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15556                                } else {
15557                                    None
15558                                }
15559                            },
15560                        );
15561                        if let Some(offset) = offset {
15562                            let task_buffer_range =
15563                                location.target.range.to_point(&buffer_snapshot);
15564                            let context_buffer_range =
15565                                task_buffer_range.to_offset(&buffer_snapshot);
15566                            let context_range = BufferOffset(context_buffer_range.start)
15567                                ..BufferOffset(context_buffer_range.end);
15568
15569                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15570                                .or_insert_with(|| RunnableTasks {
15571                                    templates: Vec::new(),
15572                                    offset,
15573                                    column: task_buffer_range.start.column,
15574                                    extra_variables: HashMap::default(),
15575                                    context_range,
15576                                })
15577                                .templates
15578                                .push((kind, task.original_task().clone()));
15579                        }
15580
15581                        acc
15582                    })
15583            }) else {
15584                return;
15585            };
15586
15587            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15588                buffer.language_settings(cx).tasks.prefer_lsp
15589            }) else {
15590                return;
15591            };
15592
15593            let rows = Self::runnable_rows(
15594                project,
15595                display_snapshot,
15596                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15597                new_rows,
15598                cx.clone(),
15599            )
15600            .await;
15601            editor
15602                .update(cx, |editor, _| {
15603                    editor.clear_tasks();
15604                    for (key, mut value) in rows {
15605                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15606                            value.templates.extend(lsp_tasks.templates);
15607                        }
15608
15609                        editor.insert_tasks(key, value);
15610                    }
15611                    for (key, value) in lsp_tasks_by_rows {
15612                        editor.insert_tasks(key, value);
15613                    }
15614                })
15615                .ok();
15616        })
15617    }
15618    fn fetch_runnable_ranges(
15619        snapshot: &DisplaySnapshot,
15620        range: Range<Anchor>,
15621    ) -> Vec<language::RunnableRange> {
15622        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15623    }
15624
15625    fn runnable_rows(
15626        project: Entity<Project>,
15627        snapshot: DisplaySnapshot,
15628        prefer_lsp: bool,
15629        runnable_ranges: Vec<RunnableRange>,
15630        cx: AsyncWindowContext,
15631    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15632        cx.spawn(async move |cx| {
15633            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15634            for mut runnable in runnable_ranges {
15635                let Some(tasks) = cx
15636                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15637                    .ok()
15638                else {
15639                    continue;
15640                };
15641                let mut tasks = tasks.await;
15642
15643                if prefer_lsp {
15644                    tasks.retain(|(task_kind, _)| {
15645                        !matches!(task_kind, TaskSourceKind::Language { .. })
15646                    });
15647                }
15648                if tasks.is_empty() {
15649                    continue;
15650                }
15651
15652                let point = runnable
15653                    .run_range
15654                    .start
15655                    .to_point(&snapshot.buffer_snapshot());
15656                let Some(row) = snapshot
15657                    .buffer_snapshot()
15658                    .buffer_line_for_row(MultiBufferRow(point.row))
15659                    .map(|(_, range)| range.start.row)
15660                else {
15661                    continue;
15662                };
15663
15664                let context_range =
15665                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15666                runnable_rows.push((
15667                    (runnable.buffer_id, row),
15668                    RunnableTasks {
15669                        templates: tasks,
15670                        offset: snapshot
15671                            .buffer_snapshot()
15672                            .anchor_before(runnable.run_range.start),
15673                        context_range,
15674                        column: point.column,
15675                        extra_variables: runnable.extra_captures,
15676                    },
15677                ));
15678            }
15679            runnable_rows
15680        })
15681    }
15682
15683    fn templates_with_tags(
15684        project: &Entity<Project>,
15685        runnable: &mut Runnable,
15686        cx: &mut App,
15687    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15688        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15689            let (worktree_id, file) = project
15690                .buffer_for_id(runnable.buffer, cx)
15691                .and_then(|buffer| buffer.read(cx).file())
15692                .map(|file| (file.worktree_id(cx), file.clone()))
15693                .unzip();
15694
15695            (
15696                project.task_store().read(cx).task_inventory().cloned(),
15697                worktree_id,
15698                file,
15699            )
15700        });
15701
15702        let tags = mem::take(&mut runnable.tags);
15703        let language = runnable.language.clone();
15704        cx.spawn(async move |cx| {
15705            let mut templates_with_tags = Vec::new();
15706            if let Some(inventory) = inventory {
15707                for RunnableTag(tag) in tags {
15708                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15709                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15710                    }) else {
15711                        return templates_with_tags;
15712                    };
15713                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15714                        move |(_, template)| {
15715                            template.tags.iter().any(|source_tag| source_tag == &tag)
15716                        },
15717                    ));
15718                }
15719            }
15720            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15721
15722            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15723                // Strongest source wins; if we have worktree tag binding, prefer that to
15724                // global and language bindings;
15725                // if we have a global binding, prefer that to language binding.
15726                let first_mismatch = templates_with_tags
15727                    .iter()
15728                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15729                if let Some(index) = first_mismatch {
15730                    templates_with_tags.truncate(index);
15731                }
15732            }
15733
15734            templates_with_tags
15735        })
15736    }
15737
15738    pub fn move_to_enclosing_bracket(
15739        &mut self,
15740        _: &MoveToEnclosingBracket,
15741        window: &mut Window,
15742        cx: &mut Context<Self>,
15743    ) {
15744        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15745        self.change_selections(Default::default(), window, cx, |s| {
15746            s.move_offsets_with(|snapshot, selection| {
15747                let Some(enclosing_bracket_ranges) =
15748                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15749                else {
15750                    return;
15751                };
15752
15753                let mut best_length = usize::MAX;
15754                let mut best_inside = false;
15755                let mut best_in_bracket_range = false;
15756                let mut best_destination = None;
15757                for (open, close) in enclosing_bracket_ranges {
15758                    let close = close.to_inclusive();
15759                    let length = close.end() - open.start;
15760                    let inside = selection.start >= open.end && selection.end <= *close.start();
15761                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15762                        || close.contains(&selection.head());
15763
15764                    // If best is next to a bracket and current isn't, skip
15765                    if !in_bracket_range && best_in_bracket_range {
15766                        continue;
15767                    }
15768
15769                    // Prefer smaller lengths unless best is inside and current isn't
15770                    if length > best_length && (best_inside || !inside) {
15771                        continue;
15772                    }
15773
15774                    best_length = length;
15775                    best_inside = inside;
15776                    best_in_bracket_range = in_bracket_range;
15777                    best_destination = Some(
15778                        if close.contains(&selection.start) && close.contains(&selection.end) {
15779                            if inside { open.end } else { open.start }
15780                        } else if inside {
15781                            *close.start()
15782                        } else {
15783                            *close.end()
15784                        },
15785                    );
15786                }
15787
15788                if let Some(destination) = best_destination {
15789                    selection.collapse_to(destination, SelectionGoal::None);
15790                }
15791            })
15792        });
15793    }
15794
15795    pub fn undo_selection(
15796        &mut self,
15797        _: &UndoSelection,
15798        window: &mut Window,
15799        cx: &mut Context<Self>,
15800    ) {
15801        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15802        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15803            self.selection_history.mode = SelectionHistoryMode::Undoing;
15804            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15805                this.end_selection(window, cx);
15806                this.change_selections(
15807                    SelectionEffects::scroll(Autoscroll::newest()),
15808                    window,
15809                    cx,
15810                    |s| s.select_anchors(entry.selections.to_vec()),
15811                );
15812            });
15813            self.selection_history.mode = SelectionHistoryMode::Normal;
15814
15815            self.select_next_state = entry.select_next_state;
15816            self.select_prev_state = entry.select_prev_state;
15817            self.add_selections_state = entry.add_selections_state;
15818        }
15819    }
15820
15821    pub fn redo_selection(
15822        &mut self,
15823        _: &RedoSelection,
15824        window: &mut Window,
15825        cx: &mut Context<Self>,
15826    ) {
15827        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15828        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15829            self.selection_history.mode = SelectionHistoryMode::Redoing;
15830            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15831                this.end_selection(window, cx);
15832                this.change_selections(
15833                    SelectionEffects::scroll(Autoscroll::newest()),
15834                    window,
15835                    cx,
15836                    |s| s.select_anchors(entry.selections.to_vec()),
15837                );
15838            });
15839            self.selection_history.mode = SelectionHistoryMode::Normal;
15840
15841            self.select_next_state = entry.select_next_state;
15842            self.select_prev_state = entry.select_prev_state;
15843            self.add_selections_state = entry.add_selections_state;
15844        }
15845    }
15846
15847    pub fn expand_excerpts(
15848        &mut self,
15849        action: &ExpandExcerpts,
15850        _: &mut Window,
15851        cx: &mut Context<Self>,
15852    ) {
15853        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15854    }
15855
15856    pub fn expand_excerpts_down(
15857        &mut self,
15858        action: &ExpandExcerptsDown,
15859        _: &mut Window,
15860        cx: &mut Context<Self>,
15861    ) {
15862        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15863    }
15864
15865    pub fn expand_excerpts_up(
15866        &mut self,
15867        action: &ExpandExcerptsUp,
15868        _: &mut Window,
15869        cx: &mut Context<Self>,
15870    ) {
15871        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15872    }
15873
15874    pub fn expand_excerpts_for_direction(
15875        &mut self,
15876        lines: u32,
15877        direction: ExpandExcerptDirection,
15878
15879        cx: &mut Context<Self>,
15880    ) {
15881        let selections = self.selections.disjoint_anchors_arc();
15882
15883        let lines = if lines == 0 {
15884            EditorSettings::get_global(cx).expand_excerpt_lines
15885        } else {
15886            lines
15887        };
15888
15889        self.buffer.update(cx, |buffer, cx| {
15890            let snapshot = buffer.snapshot(cx);
15891            let mut excerpt_ids = selections
15892                .iter()
15893                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15894                .collect::<Vec<_>>();
15895            excerpt_ids.sort();
15896            excerpt_ids.dedup();
15897            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15898        })
15899    }
15900
15901    pub fn expand_excerpt(
15902        &mut self,
15903        excerpt: ExcerptId,
15904        direction: ExpandExcerptDirection,
15905        window: &mut Window,
15906        cx: &mut Context<Self>,
15907    ) {
15908        let current_scroll_position = self.scroll_position(cx);
15909        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15910        let mut scroll = None;
15911
15912        if direction == ExpandExcerptDirection::Down {
15913            let multi_buffer = self.buffer.read(cx);
15914            let snapshot = multi_buffer.snapshot(cx);
15915            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15916                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15917                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15918            {
15919                let buffer_snapshot = buffer.read(cx).snapshot();
15920                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15921                let last_row = buffer_snapshot.max_point().row;
15922                let lines_below = last_row.saturating_sub(excerpt_end_row);
15923                if lines_below >= lines_to_expand {
15924                    scroll = Some(
15925                        current_scroll_position
15926                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
15927                    );
15928                }
15929            }
15930        }
15931        if direction == ExpandExcerptDirection::Up
15932            && self
15933                .buffer
15934                .read(cx)
15935                .snapshot(cx)
15936                .excerpt_before(excerpt)
15937                .is_none()
15938        {
15939            scroll = Some(current_scroll_position);
15940        }
15941
15942        self.buffer.update(cx, |buffer, cx| {
15943            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15944        });
15945
15946        if let Some(new_scroll_position) = scroll {
15947            self.set_scroll_position(new_scroll_position, window, cx);
15948        }
15949    }
15950
15951    pub fn go_to_singleton_buffer_point(
15952        &mut self,
15953        point: Point,
15954        window: &mut Window,
15955        cx: &mut Context<Self>,
15956    ) {
15957        self.go_to_singleton_buffer_range(point..point, window, cx);
15958    }
15959
15960    pub fn go_to_singleton_buffer_range(
15961        &mut self,
15962        range: Range<Point>,
15963        window: &mut Window,
15964        cx: &mut Context<Self>,
15965    ) {
15966        let multibuffer = self.buffer().read(cx);
15967        let Some(buffer) = multibuffer.as_singleton() else {
15968            return;
15969        };
15970        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15971            return;
15972        };
15973        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15974            return;
15975        };
15976        self.change_selections(
15977            SelectionEffects::default().nav_history(true),
15978            window,
15979            cx,
15980            |s| s.select_anchor_ranges([start..end]),
15981        );
15982    }
15983
15984    pub fn go_to_diagnostic(
15985        &mut self,
15986        action: &GoToDiagnostic,
15987        window: &mut Window,
15988        cx: &mut Context<Self>,
15989    ) {
15990        if !self.diagnostics_enabled() {
15991            return;
15992        }
15993        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15994        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15995    }
15996
15997    pub fn go_to_prev_diagnostic(
15998        &mut self,
15999        action: &GoToPreviousDiagnostic,
16000        window: &mut Window,
16001        cx: &mut Context<Self>,
16002    ) {
16003        if !self.diagnostics_enabled() {
16004            return;
16005        }
16006        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16007        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16008    }
16009
16010    pub fn go_to_diagnostic_impl(
16011        &mut self,
16012        direction: Direction,
16013        severity: GoToDiagnosticSeverityFilter,
16014        window: &mut Window,
16015        cx: &mut Context<Self>,
16016    ) {
16017        let buffer = self.buffer.read(cx).snapshot(cx);
16018        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16019
16020        let mut active_group_id = None;
16021        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16022            && active_group.active_range.start.to_offset(&buffer) == selection.start
16023        {
16024            active_group_id = Some(active_group.group_id);
16025        }
16026
16027        fn filtered<'a>(
16028            snapshot: EditorSnapshot,
16029            severity: GoToDiagnosticSeverityFilter,
16030            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16031        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16032            diagnostics
16033                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16034                .filter(|entry| entry.range.start != entry.range.end)
16035                .filter(|entry| !entry.diagnostic.is_unnecessary)
16036                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
16037        }
16038
16039        let snapshot = self.snapshot(window, cx);
16040        let before = filtered(
16041            snapshot.clone(),
16042            severity,
16043            buffer
16044                .diagnostics_in_range(0..selection.start)
16045                .filter(|entry| entry.range.start <= selection.start),
16046        );
16047        let after = filtered(
16048            snapshot,
16049            severity,
16050            buffer
16051                .diagnostics_in_range(selection.start..buffer.len())
16052                .filter(|entry| entry.range.start >= selection.start),
16053        );
16054
16055        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16056        if direction == Direction::Prev {
16057            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16058            {
16059                for diagnostic in prev_diagnostics.into_iter().rev() {
16060                    if diagnostic.range.start != selection.start
16061                        || active_group_id
16062                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16063                    {
16064                        found = Some(diagnostic);
16065                        break 'outer;
16066                    }
16067                }
16068            }
16069        } else {
16070            for diagnostic in after.chain(before) {
16071                if diagnostic.range.start != selection.start
16072                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16073                {
16074                    found = Some(diagnostic);
16075                    break;
16076                }
16077            }
16078        }
16079        let Some(next_diagnostic) = found else {
16080            return;
16081        };
16082
16083        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16084        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16085            return;
16086        };
16087        self.change_selections(Default::default(), window, cx, |s| {
16088            s.select_ranges(vec![
16089                next_diagnostic.range.start..next_diagnostic.range.start,
16090            ])
16091        });
16092        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16093        self.refresh_edit_prediction(false, true, window, cx);
16094    }
16095
16096    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16097        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16098        let snapshot = self.snapshot(window, cx);
16099        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16100        self.go_to_hunk_before_or_after_position(
16101            &snapshot,
16102            selection.head(),
16103            Direction::Next,
16104            window,
16105            cx,
16106        );
16107    }
16108
16109    pub fn go_to_hunk_before_or_after_position(
16110        &mut self,
16111        snapshot: &EditorSnapshot,
16112        position: Point,
16113        direction: Direction,
16114        window: &mut Window,
16115        cx: &mut Context<Editor>,
16116    ) {
16117        let row = if direction == Direction::Next {
16118            self.hunk_after_position(snapshot, position)
16119                .map(|hunk| hunk.row_range.start)
16120        } else {
16121            self.hunk_before_position(snapshot, position)
16122        };
16123
16124        if let Some(row) = row {
16125            let destination = Point::new(row.0, 0);
16126            let autoscroll = Autoscroll::center();
16127
16128            self.unfold_ranges(&[destination..destination], false, false, cx);
16129            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16130                s.select_ranges([destination..destination]);
16131            });
16132        }
16133    }
16134
16135    fn hunk_after_position(
16136        &mut self,
16137        snapshot: &EditorSnapshot,
16138        position: Point,
16139    ) -> Option<MultiBufferDiffHunk> {
16140        snapshot
16141            .buffer_snapshot()
16142            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16143            .find(|hunk| hunk.row_range.start.0 > position.row)
16144            .or_else(|| {
16145                snapshot
16146                    .buffer_snapshot()
16147                    .diff_hunks_in_range(Point::zero()..position)
16148                    .find(|hunk| hunk.row_range.end.0 < position.row)
16149            })
16150    }
16151
16152    fn go_to_prev_hunk(
16153        &mut self,
16154        _: &GoToPreviousHunk,
16155        window: &mut Window,
16156        cx: &mut Context<Self>,
16157    ) {
16158        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16159        let snapshot = self.snapshot(window, cx);
16160        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16161        self.go_to_hunk_before_or_after_position(
16162            &snapshot,
16163            selection.head(),
16164            Direction::Prev,
16165            window,
16166            cx,
16167        );
16168    }
16169
16170    fn hunk_before_position(
16171        &mut self,
16172        snapshot: &EditorSnapshot,
16173        position: Point,
16174    ) -> Option<MultiBufferRow> {
16175        snapshot
16176            .buffer_snapshot()
16177            .diff_hunk_before(position)
16178            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16179    }
16180
16181    fn go_to_next_change(
16182        &mut self,
16183        _: &GoToNextChange,
16184        window: &mut Window,
16185        cx: &mut Context<Self>,
16186    ) {
16187        if let Some(selections) = self
16188            .change_list
16189            .next_change(1, Direction::Next)
16190            .map(|s| s.to_vec())
16191        {
16192            self.change_selections(Default::default(), window, cx, |s| {
16193                let map = s.display_map();
16194                s.select_display_ranges(selections.iter().map(|a| {
16195                    let point = a.to_display_point(&map);
16196                    point..point
16197                }))
16198            })
16199        }
16200    }
16201
16202    fn go_to_previous_change(
16203        &mut self,
16204        _: &GoToPreviousChange,
16205        window: &mut Window,
16206        cx: &mut Context<Self>,
16207    ) {
16208        if let Some(selections) = self
16209            .change_list
16210            .next_change(1, Direction::Prev)
16211            .map(|s| s.to_vec())
16212        {
16213            self.change_selections(Default::default(), window, cx, |s| {
16214                let map = s.display_map();
16215                s.select_display_ranges(selections.iter().map(|a| {
16216                    let point = a.to_display_point(&map);
16217                    point..point
16218                }))
16219            })
16220        }
16221    }
16222
16223    pub fn go_to_next_document_highlight(
16224        &mut self,
16225        _: &GoToNextDocumentHighlight,
16226        window: &mut Window,
16227        cx: &mut Context<Self>,
16228    ) {
16229        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16230    }
16231
16232    pub fn go_to_prev_document_highlight(
16233        &mut self,
16234        _: &GoToPreviousDocumentHighlight,
16235        window: &mut Window,
16236        cx: &mut Context<Self>,
16237    ) {
16238        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16239    }
16240
16241    pub fn go_to_document_highlight_before_or_after_position(
16242        &mut self,
16243        direction: Direction,
16244        window: &mut Window,
16245        cx: &mut Context<Editor>,
16246    ) {
16247        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16248        let snapshot = self.snapshot(window, cx);
16249        let buffer = &snapshot.buffer_snapshot();
16250        let position = self
16251            .selections
16252            .newest::<Point>(&snapshot.display_snapshot)
16253            .head();
16254        let anchor_position = buffer.anchor_after(position);
16255
16256        // Get all document highlights (both read and write)
16257        let mut all_highlights = Vec::new();
16258
16259        if let Some((_, read_highlights)) = self
16260            .background_highlights
16261            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16262        {
16263            all_highlights.extend(read_highlights.iter());
16264        }
16265
16266        if let Some((_, write_highlights)) = self
16267            .background_highlights
16268            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16269        {
16270            all_highlights.extend(write_highlights.iter());
16271        }
16272
16273        if all_highlights.is_empty() {
16274            return;
16275        }
16276
16277        // Sort highlights by position
16278        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16279
16280        let target_highlight = match direction {
16281            Direction::Next => {
16282                // Find the first highlight after the current position
16283                all_highlights
16284                    .iter()
16285                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16286            }
16287            Direction::Prev => {
16288                // Find the last highlight before the current position
16289                all_highlights
16290                    .iter()
16291                    .rev()
16292                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16293            }
16294        };
16295
16296        if let Some(highlight) = target_highlight {
16297            let destination = highlight.start.to_point(buffer);
16298            let autoscroll = Autoscroll::center();
16299
16300            self.unfold_ranges(&[destination..destination], false, false, cx);
16301            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16302                s.select_ranges([destination..destination]);
16303            });
16304        }
16305    }
16306
16307    fn go_to_line<T: 'static>(
16308        &mut self,
16309        position: Anchor,
16310        highlight_color: Option<Hsla>,
16311        window: &mut Window,
16312        cx: &mut Context<Self>,
16313    ) {
16314        let snapshot = self.snapshot(window, cx).display_snapshot;
16315        let position = position.to_point(&snapshot.buffer_snapshot());
16316        let start = snapshot
16317            .buffer_snapshot()
16318            .clip_point(Point::new(position.row, 0), Bias::Left);
16319        let end = start + Point::new(1, 0);
16320        let start = snapshot.buffer_snapshot().anchor_before(start);
16321        let end = snapshot.buffer_snapshot().anchor_before(end);
16322
16323        self.highlight_rows::<T>(
16324            start..end,
16325            highlight_color
16326                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16327            Default::default(),
16328            cx,
16329        );
16330
16331        if self.buffer.read(cx).is_singleton() {
16332            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16333        }
16334    }
16335
16336    pub fn go_to_definition(
16337        &mut self,
16338        _: &GoToDefinition,
16339        window: &mut Window,
16340        cx: &mut Context<Self>,
16341    ) -> Task<Result<Navigated>> {
16342        let definition =
16343            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16344        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16345        cx.spawn_in(window, async move |editor, cx| {
16346            if definition.await? == Navigated::Yes {
16347                return Ok(Navigated::Yes);
16348            }
16349            match fallback_strategy {
16350                GoToDefinitionFallback::None => Ok(Navigated::No),
16351                GoToDefinitionFallback::FindAllReferences => {
16352                    match editor.update_in(cx, |editor, window, cx| {
16353                        editor.find_all_references(&FindAllReferences, window, cx)
16354                    })? {
16355                        Some(references) => references.await,
16356                        None => Ok(Navigated::No),
16357                    }
16358                }
16359            }
16360        })
16361    }
16362
16363    pub fn go_to_declaration(
16364        &mut self,
16365        _: &GoToDeclaration,
16366        window: &mut Window,
16367        cx: &mut Context<Self>,
16368    ) -> Task<Result<Navigated>> {
16369        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16370    }
16371
16372    pub fn go_to_declaration_split(
16373        &mut self,
16374        _: &GoToDeclaration,
16375        window: &mut Window,
16376        cx: &mut Context<Self>,
16377    ) -> Task<Result<Navigated>> {
16378        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16379    }
16380
16381    pub fn go_to_implementation(
16382        &mut self,
16383        _: &GoToImplementation,
16384        window: &mut Window,
16385        cx: &mut Context<Self>,
16386    ) -> Task<Result<Navigated>> {
16387        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16388    }
16389
16390    pub fn go_to_implementation_split(
16391        &mut self,
16392        _: &GoToImplementationSplit,
16393        window: &mut Window,
16394        cx: &mut Context<Self>,
16395    ) -> Task<Result<Navigated>> {
16396        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16397    }
16398
16399    pub fn go_to_type_definition(
16400        &mut self,
16401        _: &GoToTypeDefinition,
16402        window: &mut Window,
16403        cx: &mut Context<Self>,
16404    ) -> Task<Result<Navigated>> {
16405        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16406    }
16407
16408    pub fn go_to_definition_split(
16409        &mut self,
16410        _: &GoToDefinitionSplit,
16411        window: &mut Window,
16412        cx: &mut Context<Self>,
16413    ) -> Task<Result<Navigated>> {
16414        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16415    }
16416
16417    pub fn go_to_type_definition_split(
16418        &mut self,
16419        _: &GoToTypeDefinitionSplit,
16420        window: &mut Window,
16421        cx: &mut Context<Self>,
16422    ) -> Task<Result<Navigated>> {
16423        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16424    }
16425
16426    fn go_to_definition_of_kind(
16427        &mut self,
16428        kind: GotoDefinitionKind,
16429        split: bool,
16430        window: &mut Window,
16431        cx: &mut Context<Self>,
16432    ) -> Task<Result<Navigated>> {
16433        let Some(provider) = self.semantics_provider.clone() else {
16434            return Task::ready(Ok(Navigated::No));
16435        };
16436        let head = self
16437            .selections
16438            .newest::<usize>(&self.display_snapshot(cx))
16439            .head();
16440        let buffer = self.buffer.read(cx);
16441        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16442            return Task::ready(Ok(Navigated::No));
16443        };
16444        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16445            return Task::ready(Ok(Navigated::No));
16446        };
16447
16448        cx.spawn_in(window, async move |editor, cx| {
16449            let Some(definitions) = definitions.await? else {
16450                return Ok(Navigated::No);
16451            };
16452            let navigated = editor
16453                .update_in(cx, |editor, window, cx| {
16454                    editor.navigate_to_hover_links(
16455                        Some(kind),
16456                        definitions
16457                            .into_iter()
16458                            .filter(|location| {
16459                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16460                            })
16461                            .map(HoverLink::Text)
16462                            .collect::<Vec<_>>(),
16463                        split,
16464                        window,
16465                        cx,
16466                    )
16467                })?
16468                .await?;
16469            anyhow::Ok(navigated)
16470        })
16471    }
16472
16473    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16474        let selection = self.selections.newest_anchor();
16475        let head = selection.head();
16476        let tail = selection.tail();
16477
16478        let Some((buffer, start_position)) =
16479            self.buffer.read(cx).text_anchor_for_position(head, cx)
16480        else {
16481            return;
16482        };
16483
16484        let end_position = if head != tail {
16485            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16486                return;
16487            };
16488            Some(pos)
16489        } else {
16490            None
16491        };
16492
16493        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16494            let url = if let Some(end_pos) = end_position {
16495                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16496            } else {
16497                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16498            };
16499
16500            if let Some(url) = url {
16501                cx.update(|window, cx| {
16502                    if parse_zed_link(&url, cx).is_some() {
16503                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16504                    } else {
16505                        cx.open_url(&url);
16506                    }
16507                })?;
16508            }
16509
16510            anyhow::Ok(())
16511        });
16512
16513        url_finder.detach();
16514    }
16515
16516    pub fn open_selected_filename(
16517        &mut self,
16518        _: &OpenSelectedFilename,
16519        window: &mut Window,
16520        cx: &mut Context<Self>,
16521    ) {
16522        let Some(workspace) = self.workspace() else {
16523            return;
16524        };
16525
16526        let position = self.selections.newest_anchor().head();
16527
16528        let Some((buffer, buffer_position)) =
16529            self.buffer.read(cx).text_anchor_for_position(position, cx)
16530        else {
16531            return;
16532        };
16533
16534        let project = self.project.clone();
16535
16536        cx.spawn_in(window, async move |_, cx| {
16537            let result = find_file(&buffer, project, buffer_position, cx).await;
16538
16539            if let Some((_, path)) = result {
16540                workspace
16541                    .update_in(cx, |workspace, window, cx| {
16542                        workspace.open_resolved_path(path, window, cx)
16543                    })?
16544                    .await?;
16545            }
16546            anyhow::Ok(())
16547        })
16548        .detach();
16549    }
16550
16551    pub(crate) fn navigate_to_hover_links(
16552        &mut self,
16553        kind: Option<GotoDefinitionKind>,
16554        definitions: Vec<HoverLink>,
16555        split: bool,
16556        window: &mut Window,
16557        cx: &mut Context<Editor>,
16558    ) -> Task<Result<Navigated>> {
16559        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16560        let mut first_url_or_file = None;
16561        let definitions: Vec<_> = definitions
16562            .into_iter()
16563            .filter_map(|def| match def {
16564                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16565                HoverLink::InlayHint(lsp_location, server_id) => {
16566                    let computation =
16567                        self.compute_target_location(lsp_location, server_id, window, cx);
16568                    Some(cx.background_spawn(computation))
16569                }
16570                HoverLink::Url(url) => {
16571                    first_url_or_file = Some(Either::Left(url));
16572                    None
16573                }
16574                HoverLink::File(path) => {
16575                    first_url_or_file = Some(Either::Right(path));
16576                    None
16577                }
16578            })
16579            .collect();
16580
16581        let workspace = self.workspace();
16582
16583        cx.spawn_in(window, async move |editor, cx| {
16584            let locations: Vec<Location> = future::join_all(definitions)
16585                .await
16586                .into_iter()
16587                .filter_map(|location| location.transpose())
16588                .collect::<Result<_>>()
16589                .context("location tasks")?;
16590            let mut locations = cx.update(|_, cx| {
16591                locations
16592                    .into_iter()
16593                    .map(|location| {
16594                        let buffer = location.buffer.read(cx);
16595                        (location.buffer, location.range.to_point(buffer))
16596                    })
16597                    .into_group_map()
16598            })?;
16599            let mut num_locations = 0;
16600            for ranges in locations.values_mut() {
16601                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16602                ranges.dedup();
16603                num_locations += ranges.len();
16604            }
16605
16606            if num_locations > 1 {
16607                let Some(workspace) = workspace else {
16608                    return Ok(Navigated::No);
16609                };
16610
16611                let tab_kind = match kind {
16612                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16613                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16614                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16615                    Some(GotoDefinitionKind::Type) => "Types",
16616                };
16617                let title = editor
16618                    .update_in(cx, |_, _, cx| {
16619                        let target = locations
16620                            .iter()
16621                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16622                            .map(|(buffer, location)| {
16623                                buffer
16624                                    .read(cx)
16625                                    .text_for_range(location.clone())
16626                                    .collect::<String>()
16627                            })
16628                            .filter(|text| !text.contains('\n'))
16629                            .unique()
16630                            .take(3)
16631                            .join(", ");
16632                        if target.is_empty() {
16633                            tab_kind.to_owned()
16634                        } else {
16635                            format!("{tab_kind} for {target}")
16636                        }
16637                    })
16638                    .context("buffer title")?;
16639
16640                let opened = workspace
16641                    .update_in(cx, |workspace, window, cx| {
16642                        Self::open_locations_in_multibuffer(
16643                            workspace,
16644                            locations,
16645                            title,
16646                            split,
16647                            MultibufferSelectionMode::First,
16648                            window,
16649                            cx,
16650                        )
16651                    })
16652                    .is_ok();
16653
16654                anyhow::Ok(Navigated::from_bool(opened))
16655            } else if num_locations == 0 {
16656                // If there is one url or file, open it directly
16657                match first_url_or_file {
16658                    Some(Either::Left(url)) => {
16659                        cx.update(|_, cx| cx.open_url(&url))?;
16660                        Ok(Navigated::Yes)
16661                    }
16662                    Some(Either::Right(path)) => {
16663                        let Some(workspace) = workspace else {
16664                            return Ok(Navigated::No);
16665                        };
16666
16667                        workspace
16668                            .update_in(cx, |workspace, window, cx| {
16669                                workspace.open_resolved_path(path, window, cx)
16670                            })?
16671                            .await?;
16672                        Ok(Navigated::Yes)
16673                    }
16674                    None => Ok(Navigated::No),
16675                }
16676            } else {
16677                let Some(workspace) = workspace else {
16678                    return Ok(Navigated::No);
16679                };
16680
16681                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16682                let target_range = target_ranges.first().unwrap().clone();
16683
16684                editor.update_in(cx, |editor, window, cx| {
16685                    let range = target_range.to_point(target_buffer.read(cx));
16686                    let range = editor.range_for_match(&range, false);
16687                    let range = collapse_multiline_range(range);
16688
16689                    if !split
16690                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16691                    {
16692                        editor.go_to_singleton_buffer_range(range, window, cx);
16693                    } else {
16694                        let pane = workspace.read(cx).active_pane().clone();
16695                        window.defer(cx, move |window, cx| {
16696                            let target_editor: Entity<Self> =
16697                                workspace.update(cx, |workspace, cx| {
16698                                    let pane = if split {
16699                                        workspace.adjacent_pane(window, cx)
16700                                    } else {
16701                                        workspace.active_pane().clone()
16702                                    };
16703
16704                                    workspace.open_project_item(
16705                                        pane,
16706                                        target_buffer.clone(),
16707                                        true,
16708                                        true,
16709                                        window,
16710                                        cx,
16711                                    )
16712                                });
16713                            target_editor.update(cx, |target_editor, cx| {
16714                                // When selecting a definition in a different buffer, disable the nav history
16715                                // to avoid creating a history entry at the previous cursor location.
16716                                pane.update(cx, |pane, _| pane.disable_history());
16717                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16718                                pane.update(cx, |pane, _| pane.enable_history());
16719                            });
16720                        });
16721                    }
16722                    Navigated::Yes
16723                })
16724            }
16725        })
16726    }
16727
16728    fn compute_target_location(
16729        &self,
16730        lsp_location: lsp::Location,
16731        server_id: LanguageServerId,
16732        window: &mut Window,
16733        cx: &mut Context<Self>,
16734    ) -> Task<anyhow::Result<Option<Location>>> {
16735        let Some(project) = self.project.clone() else {
16736            return Task::ready(Ok(None));
16737        };
16738
16739        cx.spawn_in(window, async move |editor, cx| {
16740            let location_task = editor.update(cx, |_, cx| {
16741                project.update(cx, |project, cx| {
16742                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16743                })
16744            })?;
16745            let location = Some({
16746                let target_buffer_handle = location_task.await.context("open local buffer")?;
16747                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16748                    let target_start = target_buffer
16749                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16750                    let target_end = target_buffer
16751                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16752                    target_buffer.anchor_after(target_start)
16753                        ..target_buffer.anchor_before(target_end)
16754                })?;
16755                Location {
16756                    buffer: target_buffer_handle,
16757                    range,
16758                }
16759            });
16760            Ok(location)
16761        })
16762    }
16763
16764    fn go_to_next_reference(
16765        &mut self,
16766        _: &GoToNextReference,
16767        window: &mut Window,
16768        cx: &mut Context<Self>,
16769    ) {
16770        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16771        if let Some(task) = task {
16772            task.detach();
16773        };
16774    }
16775
16776    fn go_to_prev_reference(
16777        &mut self,
16778        _: &GoToPreviousReference,
16779        window: &mut Window,
16780        cx: &mut Context<Self>,
16781    ) {
16782        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16783        if let Some(task) = task {
16784            task.detach();
16785        };
16786    }
16787
16788    pub fn go_to_reference_before_or_after_position(
16789        &mut self,
16790        direction: Direction,
16791        count: usize,
16792        window: &mut Window,
16793        cx: &mut Context<Self>,
16794    ) -> Option<Task<Result<()>>> {
16795        let selection = self.selections.newest_anchor();
16796        let head = selection.head();
16797
16798        let multi_buffer = self.buffer.read(cx);
16799
16800        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
16801        let workspace = self.workspace()?;
16802        let project = workspace.read(cx).project().clone();
16803        let references =
16804            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
16805        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
16806            let Some(locations) = references.await? else {
16807                return Ok(());
16808            };
16809
16810            if locations.is_empty() {
16811                // totally normal - the cursor may be on something which is not
16812                // a symbol (e.g. a keyword)
16813                log::info!("no references found under cursor");
16814                return Ok(());
16815            }
16816
16817            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
16818
16819            let multi_buffer_snapshot =
16820                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
16821
16822            let (locations, current_location_index) =
16823                multi_buffer.update(cx, |multi_buffer, cx| {
16824                    let mut locations = locations
16825                        .into_iter()
16826                        .filter_map(|loc| {
16827                            let start = multi_buffer.buffer_anchor_to_anchor(
16828                                &loc.buffer,
16829                                loc.range.start,
16830                                cx,
16831                            )?;
16832                            let end = multi_buffer.buffer_anchor_to_anchor(
16833                                &loc.buffer,
16834                                loc.range.end,
16835                                cx,
16836                            )?;
16837                            Some(start..end)
16838                        })
16839                        .collect::<Vec<_>>();
16840
16841                    // There is an O(n) implementation, but given this list will be
16842                    // small (usually <100 items), the extra O(log(n)) factor isn't
16843                    // worth the (surprisingly large amount of) extra complexity.
16844                    locations
16845                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
16846
16847                    let head_offset = head.to_offset(&multi_buffer_snapshot);
16848
16849                    let current_location_index = locations.iter().position(|loc| {
16850                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
16851                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
16852                    });
16853
16854                    (locations, current_location_index)
16855                })?;
16856
16857            let Some(current_location_index) = current_location_index else {
16858                // This indicates something has gone wrong, because we already
16859                // handle the "no references" case above
16860                log::error!(
16861                    "failed to find current reference under cursor. Total references: {}",
16862                    locations.len()
16863                );
16864                return Ok(());
16865            };
16866
16867            let destination_location_index = match direction {
16868                Direction::Next => (current_location_index + count) % locations.len(),
16869                Direction::Prev => {
16870                    (current_location_index + locations.len() - count % locations.len())
16871                        % locations.len()
16872                }
16873            };
16874
16875            // TODO(cameron): is this needed?
16876            // the thinking is to avoid "jumping to the current location" (avoid
16877            // polluting "jumplist" in vim terms)
16878            if current_location_index == destination_location_index {
16879                return Ok(());
16880            }
16881
16882            let Range { start, end } = locations[destination_location_index];
16883
16884            editor.update_in(cx, |editor, window, cx| {
16885                let effects = SelectionEffects::default();
16886
16887                editor.unfold_ranges(&[start..end], false, false, cx);
16888                editor.change_selections(effects, window, cx, |s| {
16889                    s.select_ranges([start..start]);
16890                });
16891            })?;
16892
16893            Ok(())
16894        }))
16895    }
16896
16897    pub fn find_all_references(
16898        &mut self,
16899        _: &FindAllReferences,
16900        window: &mut Window,
16901        cx: &mut Context<Self>,
16902    ) -> Option<Task<Result<Navigated>>> {
16903        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16904        let multi_buffer = self.buffer.read(cx);
16905        let head = selection.head();
16906
16907        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16908        let head_anchor = multi_buffer_snapshot.anchor_at(
16909            head,
16910            if head < selection.tail() {
16911                Bias::Right
16912            } else {
16913                Bias::Left
16914            },
16915        );
16916
16917        match self
16918            .find_all_references_task_sources
16919            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16920        {
16921            Ok(_) => {
16922                log::info!(
16923                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16924                );
16925                return None;
16926            }
16927            Err(i) => {
16928                self.find_all_references_task_sources.insert(i, head_anchor);
16929            }
16930        }
16931
16932        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16933        let workspace = self.workspace()?;
16934        let project = workspace.read(cx).project().clone();
16935        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16936        Some(cx.spawn_in(window, async move |editor, cx| {
16937            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16938                if let Ok(i) = editor
16939                    .find_all_references_task_sources
16940                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16941                {
16942                    editor.find_all_references_task_sources.remove(i);
16943                }
16944            });
16945
16946            let Some(locations) = references.await? else {
16947                return anyhow::Ok(Navigated::No);
16948            };
16949            let mut locations = cx.update(|_, cx| {
16950                locations
16951                    .into_iter()
16952                    .map(|location| {
16953                        let buffer = location.buffer.read(cx);
16954                        (location.buffer, location.range.to_point(buffer))
16955                    })
16956                    .into_group_map()
16957            })?;
16958            if locations.is_empty() {
16959                return anyhow::Ok(Navigated::No);
16960            }
16961            for ranges in locations.values_mut() {
16962                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16963                ranges.dedup();
16964            }
16965
16966            workspace.update_in(cx, |workspace, window, cx| {
16967                let target = locations
16968                    .iter()
16969                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16970                    .map(|(buffer, location)| {
16971                        buffer
16972                            .read(cx)
16973                            .text_for_range(location.clone())
16974                            .collect::<String>()
16975                    })
16976                    .filter(|text| !text.contains('\n'))
16977                    .unique()
16978                    .take(3)
16979                    .join(", ");
16980                let title = if target.is_empty() {
16981                    "References".to_owned()
16982                } else {
16983                    format!("References to {target}")
16984                };
16985                Self::open_locations_in_multibuffer(
16986                    workspace,
16987                    locations,
16988                    title,
16989                    false,
16990                    MultibufferSelectionMode::First,
16991                    window,
16992                    cx,
16993                );
16994                Navigated::Yes
16995            })
16996        }))
16997    }
16998
16999    /// Opens a multibuffer with the given project locations in it
17000    pub fn open_locations_in_multibuffer(
17001        workspace: &mut Workspace,
17002        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17003        title: String,
17004        split: bool,
17005        multibuffer_selection_mode: MultibufferSelectionMode,
17006        window: &mut Window,
17007        cx: &mut Context<Workspace>,
17008    ) {
17009        if locations.is_empty() {
17010            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17011            return;
17012        }
17013
17014        let capability = workspace.project().read(cx).capability();
17015        let mut ranges = <Vec<Range<Anchor>>>::new();
17016
17017        // a key to find existing multibuffer editors with the same set of locations
17018        // to prevent us from opening more and more multibuffer tabs for searches and the like
17019        let mut key = (title.clone(), vec![]);
17020        let excerpt_buffer = cx.new(|cx| {
17021            let key = &mut key.1;
17022            let mut multibuffer = MultiBuffer::new(capability);
17023            for (buffer, mut ranges_for_buffer) in locations {
17024                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17025                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17026                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17027                    PathKey::for_buffer(&buffer, cx),
17028                    buffer.clone(),
17029                    ranges_for_buffer,
17030                    multibuffer_context_lines(cx),
17031                    cx,
17032                );
17033                ranges.extend(new_ranges)
17034            }
17035
17036            multibuffer.with_title(title)
17037        });
17038        let existing = workspace.active_pane().update(cx, |pane, cx| {
17039            pane.items()
17040                .filter_map(|item| item.downcast::<Editor>())
17041                .find(|editor| {
17042                    editor
17043                        .read(cx)
17044                        .lookup_key
17045                        .as_ref()
17046                        .and_then(|it| {
17047                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17048                        })
17049                        .is_some_and(|it| *it == key)
17050                })
17051        });
17052        let editor = existing.unwrap_or_else(|| {
17053            cx.new(|cx| {
17054                let mut editor = Editor::for_multibuffer(
17055                    excerpt_buffer,
17056                    Some(workspace.project().clone()),
17057                    window,
17058                    cx,
17059                );
17060                editor.lookup_key = Some(Box::new(key));
17061                editor
17062            })
17063        });
17064        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17065            MultibufferSelectionMode::First => {
17066                if let Some(first_range) = ranges.first() {
17067                    editor.change_selections(
17068                        SelectionEffects::no_scroll(),
17069                        window,
17070                        cx,
17071                        |selections| {
17072                            selections.clear_disjoint();
17073                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17074                        },
17075                    );
17076                }
17077                editor.highlight_background::<Self>(
17078                    &ranges,
17079                    |theme| theme.colors().editor_highlighted_line_background,
17080                    cx,
17081                );
17082            }
17083            MultibufferSelectionMode::All => {
17084                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17085                    selections.clear_disjoint();
17086                    selections.select_anchor_ranges(ranges);
17087                });
17088            }
17089        });
17090
17091        let item = Box::new(editor);
17092        let item_id = item.item_id();
17093
17094        if split {
17095            let pane = workspace.adjacent_pane(window, cx);
17096            workspace.add_item(pane, item, None, true, true, window, cx);
17097        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17098            let (preview_item_id, preview_item_idx) =
17099                workspace.active_pane().read_with(cx, |pane, _| {
17100                    (pane.preview_item_id(), pane.preview_item_idx())
17101                });
17102
17103            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17104
17105            if let Some(preview_item_id) = preview_item_id {
17106                workspace.active_pane().update(cx, |pane, cx| {
17107                    pane.remove_item(preview_item_id, false, false, window, cx);
17108                });
17109            }
17110        } else {
17111            workspace.add_item_to_active_pane(item, None, true, window, cx);
17112        }
17113        workspace.active_pane().update(cx, |pane, cx| {
17114            pane.set_preview_item_id(Some(item_id), cx);
17115        });
17116    }
17117
17118    pub fn rename(
17119        &mut self,
17120        _: &Rename,
17121        window: &mut Window,
17122        cx: &mut Context<Self>,
17123    ) -> Option<Task<Result<()>>> {
17124        use language::ToOffset as _;
17125
17126        let provider = self.semantics_provider.clone()?;
17127        let selection = self.selections.newest_anchor().clone();
17128        let (cursor_buffer, cursor_buffer_position) = self
17129            .buffer
17130            .read(cx)
17131            .text_anchor_for_position(selection.head(), cx)?;
17132        let (tail_buffer, cursor_buffer_position_end) = self
17133            .buffer
17134            .read(cx)
17135            .text_anchor_for_position(selection.tail(), cx)?;
17136        if tail_buffer != cursor_buffer {
17137            return None;
17138        }
17139
17140        let snapshot = cursor_buffer.read(cx).snapshot();
17141        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17142        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17143        let prepare_rename = provider
17144            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17145            .unwrap_or_else(|| Task::ready(Ok(None)));
17146        drop(snapshot);
17147
17148        Some(cx.spawn_in(window, async move |this, cx| {
17149            let rename_range = if let Some(range) = prepare_rename.await? {
17150                Some(range)
17151            } else {
17152                this.update(cx, |this, cx| {
17153                    let buffer = this.buffer.read(cx).snapshot(cx);
17154                    let mut buffer_highlights = this
17155                        .document_highlights_for_position(selection.head(), &buffer)
17156                        .filter(|highlight| {
17157                            highlight.start.excerpt_id == selection.head().excerpt_id
17158                                && highlight.end.excerpt_id == selection.head().excerpt_id
17159                        });
17160                    buffer_highlights
17161                        .next()
17162                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17163                })?
17164            };
17165            if let Some(rename_range) = rename_range {
17166                this.update_in(cx, |this, window, cx| {
17167                    let snapshot = cursor_buffer.read(cx).snapshot();
17168                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17169                    let cursor_offset_in_rename_range =
17170                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17171                    let cursor_offset_in_rename_range_end =
17172                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17173
17174                    this.take_rename(false, window, cx);
17175                    let buffer = this.buffer.read(cx).read(cx);
17176                    let cursor_offset = selection.head().to_offset(&buffer);
17177                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17178                    let rename_end = rename_start + rename_buffer_range.len();
17179                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17180                    let mut old_highlight_id = None;
17181                    let old_name: Arc<str> = buffer
17182                        .chunks(rename_start..rename_end, true)
17183                        .map(|chunk| {
17184                            if old_highlight_id.is_none() {
17185                                old_highlight_id = chunk.syntax_highlight_id;
17186                            }
17187                            chunk.text
17188                        })
17189                        .collect::<String>()
17190                        .into();
17191
17192                    drop(buffer);
17193
17194                    // Position the selection in the rename editor so that it matches the current selection.
17195                    this.show_local_selections = false;
17196                    let rename_editor = cx.new(|cx| {
17197                        let mut editor = Editor::single_line(window, cx);
17198                        editor.buffer.update(cx, |buffer, cx| {
17199                            buffer.edit([(0..0, old_name.clone())], None, cx)
17200                        });
17201                        let rename_selection_range = match cursor_offset_in_rename_range
17202                            .cmp(&cursor_offset_in_rename_range_end)
17203                        {
17204                            Ordering::Equal => {
17205                                editor.select_all(&SelectAll, window, cx);
17206                                return editor;
17207                            }
17208                            Ordering::Less => {
17209                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17210                            }
17211                            Ordering::Greater => {
17212                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17213                            }
17214                        };
17215                        if rename_selection_range.end > old_name.len() {
17216                            editor.select_all(&SelectAll, window, cx);
17217                        } else {
17218                            editor.change_selections(Default::default(), window, cx, |s| {
17219                                s.select_ranges([rename_selection_range]);
17220                            });
17221                        }
17222                        editor
17223                    });
17224                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17225                        if e == &EditorEvent::Focused {
17226                            cx.emit(EditorEvent::FocusedIn)
17227                        }
17228                    })
17229                    .detach();
17230
17231                    let write_highlights =
17232                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17233                    let read_highlights =
17234                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17235                    let ranges = write_highlights
17236                        .iter()
17237                        .flat_map(|(_, ranges)| ranges.iter())
17238                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17239                        .cloned()
17240                        .collect();
17241
17242                    this.highlight_text::<Rename>(
17243                        ranges,
17244                        HighlightStyle {
17245                            fade_out: Some(0.6),
17246                            ..Default::default()
17247                        },
17248                        cx,
17249                    );
17250                    let rename_focus_handle = rename_editor.focus_handle(cx);
17251                    window.focus(&rename_focus_handle);
17252                    let block_id = this.insert_blocks(
17253                        [BlockProperties {
17254                            style: BlockStyle::Flex,
17255                            placement: BlockPlacement::Below(range.start),
17256                            height: Some(1),
17257                            render: Arc::new({
17258                                let rename_editor = rename_editor.clone();
17259                                move |cx: &mut BlockContext| {
17260                                    let mut text_style = cx.editor_style.text.clone();
17261                                    if let Some(highlight_style) = old_highlight_id
17262                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17263                                    {
17264                                        text_style = text_style.highlight(highlight_style);
17265                                    }
17266                                    div()
17267                                        .block_mouse_except_scroll()
17268                                        .pl(cx.anchor_x)
17269                                        .child(EditorElement::new(
17270                                            &rename_editor,
17271                                            EditorStyle {
17272                                                background: cx.theme().system().transparent,
17273                                                local_player: cx.editor_style.local_player,
17274                                                text: text_style,
17275                                                scrollbar_width: cx.editor_style.scrollbar_width,
17276                                                syntax: cx.editor_style.syntax.clone(),
17277                                                status: cx.editor_style.status.clone(),
17278                                                inlay_hints_style: HighlightStyle {
17279                                                    font_weight: Some(FontWeight::BOLD),
17280                                                    ..make_inlay_hints_style(cx.app)
17281                                                },
17282                                                edit_prediction_styles: make_suggestion_styles(
17283                                                    cx.app,
17284                                                ),
17285                                                ..EditorStyle::default()
17286                                            },
17287                                        ))
17288                                        .into_any_element()
17289                                }
17290                            }),
17291                            priority: 0,
17292                        }],
17293                        Some(Autoscroll::fit()),
17294                        cx,
17295                    )[0];
17296                    this.pending_rename = Some(RenameState {
17297                        range,
17298                        old_name,
17299                        editor: rename_editor,
17300                        block_id,
17301                    });
17302                })?;
17303            }
17304
17305            Ok(())
17306        }))
17307    }
17308
17309    pub fn confirm_rename(
17310        &mut self,
17311        _: &ConfirmRename,
17312        window: &mut Window,
17313        cx: &mut Context<Self>,
17314    ) -> Option<Task<Result<()>>> {
17315        let rename = self.take_rename(false, window, cx)?;
17316        let workspace = self.workspace()?.downgrade();
17317        let (buffer, start) = self
17318            .buffer
17319            .read(cx)
17320            .text_anchor_for_position(rename.range.start, cx)?;
17321        let (end_buffer, _) = self
17322            .buffer
17323            .read(cx)
17324            .text_anchor_for_position(rename.range.end, cx)?;
17325        if buffer != end_buffer {
17326            return None;
17327        }
17328
17329        let old_name = rename.old_name;
17330        let new_name = rename.editor.read(cx).text(cx);
17331
17332        let rename = self.semantics_provider.as_ref()?.perform_rename(
17333            &buffer,
17334            start,
17335            new_name.clone(),
17336            cx,
17337        )?;
17338
17339        Some(cx.spawn_in(window, async move |editor, cx| {
17340            let project_transaction = rename.await?;
17341            Self::open_project_transaction(
17342                &editor,
17343                workspace,
17344                project_transaction,
17345                format!("Rename: {}{}", old_name, new_name),
17346                cx,
17347            )
17348            .await?;
17349
17350            editor.update(cx, |editor, cx| {
17351                editor.refresh_document_highlights(cx);
17352            })?;
17353            Ok(())
17354        }))
17355    }
17356
17357    fn take_rename(
17358        &mut self,
17359        moving_cursor: bool,
17360        window: &mut Window,
17361        cx: &mut Context<Self>,
17362    ) -> Option<RenameState> {
17363        let rename = self.pending_rename.take()?;
17364        if rename.editor.focus_handle(cx).is_focused(window) {
17365            window.focus(&self.focus_handle);
17366        }
17367
17368        self.remove_blocks(
17369            [rename.block_id].into_iter().collect(),
17370            Some(Autoscroll::fit()),
17371            cx,
17372        );
17373        self.clear_highlights::<Rename>(cx);
17374        self.show_local_selections = true;
17375
17376        if moving_cursor {
17377            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17378                editor
17379                    .selections
17380                    .newest::<usize>(&editor.display_snapshot(cx))
17381                    .head()
17382            });
17383
17384            // Update the selection to match the position of the selection inside
17385            // the rename editor.
17386            let snapshot = self.buffer.read(cx).read(cx);
17387            let rename_range = rename.range.to_offset(&snapshot);
17388            let cursor_in_editor = snapshot
17389                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17390                .min(rename_range.end);
17391            drop(snapshot);
17392
17393            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17394                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17395            });
17396        } else {
17397            self.refresh_document_highlights(cx);
17398        }
17399
17400        Some(rename)
17401    }
17402
17403    pub fn pending_rename(&self) -> Option<&RenameState> {
17404        self.pending_rename.as_ref()
17405    }
17406
17407    fn format(
17408        &mut self,
17409        _: &Format,
17410        window: &mut Window,
17411        cx: &mut Context<Self>,
17412    ) -> Option<Task<Result<()>>> {
17413        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17414
17415        let project = match &self.project {
17416            Some(project) => project.clone(),
17417            None => return None,
17418        };
17419
17420        Some(self.perform_format(
17421            project,
17422            FormatTrigger::Manual,
17423            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17424            window,
17425            cx,
17426        ))
17427    }
17428
17429    fn format_selections(
17430        &mut self,
17431        _: &FormatSelections,
17432        window: &mut Window,
17433        cx: &mut Context<Self>,
17434    ) -> Option<Task<Result<()>>> {
17435        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17436
17437        let project = match &self.project {
17438            Some(project) => project.clone(),
17439            None => return None,
17440        };
17441
17442        let ranges = self
17443            .selections
17444            .all_adjusted(&self.display_snapshot(cx))
17445            .into_iter()
17446            .map(|selection| selection.range())
17447            .collect_vec();
17448
17449        Some(self.perform_format(
17450            project,
17451            FormatTrigger::Manual,
17452            FormatTarget::Ranges(ranges),
17453            window,
17454            cx,
17455        ))
17456    }
17457
17458    fn perform_format(
17459        &mut self,
17460        project: Entity<Project>,
17461        trigger: FormatTrigger,
17462        target: FormatTarget,
17463        window: &mut Window,
17464        cx: &mut Context<Self>,
17465    ) -> Task<Result<()>> {
17466        let buffer = self.buffer.clone();
17467        let (buffers, target) = match target {
17468            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17469            FormatTarget::Ranges(selection_ranges) => {
17470                let multi_buffer = buffer.read(cx);
17471                let snapshot = multi_buffer.read(cx);
17472                let mut buffers = HashSet::default();
17473                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17474                    BTreeMap::new();
17475                for selection_range in selection_ranges {
17476                    for (buffer, buffer_range, _) in
17477                        snapshot.range_to_buffer_ranges(selection_range)
17478                    {
17479                        let buffer_id = buffer.remote_id();
17480                        let start = buffer.anchor_before(buffer_range.start);
17481                        let end = buffer.anchor_after(buffer_range.end);
17482                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17483                        buffer_id_to_ranges
17484                            .entry(buffer_id)
17485                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17486                            .or_insert_with(|| vec![start..end]);
17487                    }
17488                }
17489                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17490            }
17491        };
17492
17493        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17494        let selections_prev = transaction_id_prev
17495            .and_then(|transaction_id_prev| {
17496                // default to selections as they were after the last edit, if we have them,
17497                // instead of how they are now.
17498                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17499                // will take you back to where you made the last edit, instead of staying where you scrolled
17500                self.selection_history
17501                    .transaction(transaction_id_prev)
17502                    .map(|t| t.0.clone())
17503            })
17504            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17505
17506        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17507        let format = project.update(cx, |project, cx| {
17508            project.format(buffers, target, true, trigger, cx)
17509        });
17510
17511        cx.spawn_in(window, async move |editor, cx| {
17512            let transaction = futures::select_biased! {
17513                transaction = format.log_err().fuse() => transaction,
17514                () = timeout => {
17515                    log::warn!("timed out waiting for formatting");
17516                    None
17517                }
17518            };
17519
17520            buffer
17521                .update(cx, |buffer, cx| {
17522                    if let Some(transaction) = transaction
17523                        && !buffer.is_singleton()
17524                    {
17525                        buffer.push_transaction(&transaction.0, cx);
17526                    }
17527                    cx.notify();
17528                })
17529                .ok();
17530
17531            if let Some(transaction_id_now) =
17532                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17533            {
17534                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17535                if has_new_transaction {
17536                    _ = editor.update(cx, |editor, _| {
17537                        editor
17538                            .selection_history
17539                            .insert_transaction(transaction_id_now, selections_prev);
17540                    });
17541                }
17542            }
17543
17544            Ok(())
17545        })
17546    }
17547
17548    fn organize_imports(
17549        &mut self,
17550        _: &OrganizeImports,
17551        window: &mut Window,
17552        cx: &mut Context<Self>,
17553    ) -> Option<Task<Result<()>>> {
17554        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17555        let project = match &self.project {
17556            Some(project) => project.clone(),
17557            None => return None,
17558        };
17559        Some(self.perform_code_action_kind(
17560            project,
17561            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17562            window,
17563            cx,
17564        ))
17565    }
17566
17567    fn perform_code_action_kind(
17568        &mut self,
17569        project: Entity<Project>,
17570        kind: CodeActionKind,
17571        window: &mut Window,
17572        cx: &mut Context<Self>,
17573    ) -> Task<Result<()>> {
17574        let buffer = self.buffer.clone();
17575        let buffers = buffer.read(cx).all_buffers();
17576        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17577        let apply_action = project.update(cx, |project, cx| {
17578            project.apply_code_action_kind(buffers, kind, true, cx)
17579        });
17580        cx.spawn_in(window, async move |_, cx| {
17581            let transaction = futures::select_biased! {
17582                () = timeout => {
17583                    log::warn!("timed out waiting for executing code action");
17584                    None
17585                }
17586                transaction = apply_action.log_err().fuse() => transaction,
17587            };
17588            buffer
17589                .update(cx, |buffer, cx| {
17590                    // check if we need this
17591                    if let Some(transaction) = transaction
17592                        && !buffer.is_singleton()
17593                    {
17594                        buffer.push_transaction(&transaction.0, cx);
17595                    }
17596                    cx.notify();
17597                })
17598                .ok();
17599            Ok(())
17600        })
17601    }
17602
17603    pub fn restart_language_server(
17604        &mut self,
17605        _: &RestartLanguageServer,
17606        _: &mut Window,
17607        cx: &mut Context<Self>,
17608    ) {
17609        if let Some(project) = self.project.clone() {
17610            self.buffer.update(cx, |multi_buffer, cx| {
17611                project.update(cx, |project, cx| {
17612                    project.restart_language_servers_for_buffers(
17613                        multi_buffer.all_buffers().into_iter().collect(),
17614                        HashSet::default(),
17615                        cx,
17616                    );
17617                });
17618            })
17619        }
17620    }
17621
17622    pub fn stop_language_server(
17623        &mut self,
17624        _: &StopLanguageServer,
17625        _: &mut Window,
17626        cx: &mut Context<Self>,
17627    ) {
17628        if let Some(project) = self.project.clone() {
17629            self.buffer.update(cx, |multi_buffer, cx| {
17630                project.update(cx, |project, cx| {
17631                    project.stop_language_servers_for_buffers(
17632                        multi_buffer.all_buffers().into_iter().collect(),
17633                        HashSet::default(),
17634                        cx,
17635                    );
17636                });
17637            });
17638            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17639        }
17640    }
17641
17642    fn cancel_language_server_work(
17643        workspace: &mut Workspace,
17644        _: &actions::CancelLanguageServerWork,
17645        _: &mut Window,
17646        cx: &mut Context<Workspace>,
17647    ) {
17648        let project = workspace.project();
17649        let buffers = workspace
17650            .active_item(cx)
17651            .and_then(|item| item.act_as::<Editor>(cx))
17652            .map_or(HashSet::default(), |editor| {
17653                editor.read(cx).buffer.read(cx).all_buffers()
17654            });
17655        project.update(cx, |project, cx| {
17656            project.cancel_language_server_work_for_buffers(buffers, cx);
17657        });
17658    }
17659
17660    fn show_character_palette(
17661        &mut self,
17662        _: &ShowCharacterPalette,
17663        window: &mut Window,
17664        _: &mut Context<Self>,
17665    ) {
17666        window.show_character_palette();
17667    }
17668
17669    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17670        if !self.diagnostics_enabled() {
17671            return;
17672        }
17673
17674        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17675            let buffer = self.buffer.read(cx).snapshot(cx);
17676            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17677            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17678            let is_valid = buffer
17679                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17680                .any(|entry| {
17681                    entry.diagnostic.is_primary
17682                        && !entry.range.is_empty()
17683                        && entry.range.start == primary_range_start
17684                        && entry.diagnostic.message == active_diagnostics.active_message
17685                });
17686
17687            if !is_valid {
17688                self.dismiss_diagnostics(cx);
17689            }
17690        }
17691    }
17692
17693    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17694        match &self.active_diagnostics {
17695            ActiveDiagnostic::Group(group) => Some(group),
17696            _ => None,
17697        }
17698    }
17699
17700    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17701        if !self.diagnostics_enabled() {
17702            return;
17703        }
17704        self.dismiss_diagnostics(cx);
17705        self.active_diagnostics = ActiveDiagnostic::All;
17706    }
17707
17708    fn activate_diagnostics(
17709        &mut self,
17710        buffer_id: BufferId,
17711        diagnostic: DiagnosticEntryRef<'_, usize>,
17712        window: &mut Window,
17713        cx: &mut Context<Self>,
17714    ) {
17715        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17716            return;
17717        }
17718        self.dismiss_diagnostics(cx);
17719        let snapshot = self.snapshot(window, cx);
17720        let buffer = self.buffer.read(cx).snapshot(cx);
17721        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17722            return;
17723        };
17724
17725        let diagnostic_group = buffer
17726            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17727            .collect::<Vec<_>>();
17728
17729        let blocks =
17730            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17731
17732        let blocks = self.display_map.update(cx, |display_map, cx| {
17733            display_map.insert_blocks(blocks, cx).into_iter().collect()
17734        });
17735        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17736            active_range: buffer.anchor_before(diagnostic.range.start)
17737                ..buffer.anchor_after(diagnostic.range.end),
17738            active_message: diagnostic.diagnostic.message.clone(),
17739            group_id: diagnostic.diagnostic.group_id,
17740            blocks,
17741        });
17742        cx.notify();
17743    }
17744
17745    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17746        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17747            return;
17748        };
17749
17750        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17751        if let ActiveDiagnostic::Group(group) = prev {
17752            self.display_map.update(cx, |display_map, cx| {
17753                display_map.remove_blocks(group.blocks, cx);
17754            });
17755            cx.notify();
17756        }
17757    }
17758
17759    /// Disable inline diagnostics rendering for this editor.
17760    pub fn disable_inline_diagnostics(&mut self) {
17761        self.inline_diagnostics_enabled = false;
17762        self.inline_diagnostics_update = Task::ready(());
17763        self.inline_diagnostics.clear();
17764    }
17765
17766    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17767        self.diagnostics_enabled = false;
17768        self.dismiss_diagnostics(cx);
17769        self.inline_diagnostics_update = Task::ready(());
17770        self.inline_diagnostics.clear();
17771    }
17772
17773    pub fn disable_word_completions(&mut self) {
17774        self.word_completions_enabled = false;
17775    }
17776
17777    pub fn diagnostics_enabled(&self) -> bool {
17778        self.diagnostics_enabled && self.mode.is_full()
17779    }
17780
17781    pub fn inline_diagnostics_enabled(&self) -> bool {
17782        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17783    }
17784
17785    pub fn show_inline_diagnostics(&self) -> bool {
17786        self.show_inline_diagnostics
17787    }
17788
17789    pub fn toggle_inline_diagnostics(
17790        &mut self,
17791        _: &ToggleInlineDiagnostics,
17792        window: &mut Window,
17793        cx: &mut Context<Editor>,
17794    ) {
17795        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17796        self.refresh_inline_diagnostics(false, window, cx);
17797    }
17798
17799    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17800        self.diagnostics_max_severity = severity;
17801        self.display_map.update(cx, |display_map, _| {
17802            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17803        });
17804    }
17805
17806    pub fn toggle_diagnostics(
17807        &mut self,
17808        _: &ToggleDiagnostics,
17809        window: &mut Window,
17810        cx: &mut Context<Editor>,
17811    ) {
17812        if !self.diagnostics_enabled() {
17813            return;
17814        }
17815
17816        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17817            EditorSettings::get_global(cx)
17818                .diagnostics_max_severity
17819                .filter(|severity| severity != &DiagnosticSeverity::Off)
17820                .unwrap_or(DiagnosticSeverity::Hint)
17821        } else {
17822            DiagnosticSeverity::Off
17823        };
17824        self.set_max_diagnostics_severity(new_severity, cx);
17825        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17826            self.active_diagnostics = ActiveDiagnostic::None;
17827            self.inline_diagnostics_update = Task::ready(());
17828            self.inline_diagnostics.clear();
17829        } else {
17830            self.refresh_inline_diagnostics(false, window, cx);
17831        }
17832
17833        cx.notify();
17834    }
17835
17836    pub fn toggle_minimap(
17837        &mut self,
17838        _: &ToggleMinimap,
17839        window: &mut Window,
17840        cx: &mut Context<Editor>,
17841    ) {
17842        if self.supports_minimap(cx) {
17843            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17844        }
17845    }
17846
17847    fn refresh_inline_diagnostics(
17848        &mut self,
17849        debounce: bool,
17850        window: &mut Window,
17851        cx: &mut Context<Self>,
17852    ) {
17853        let max_severity = ProjectSettings::get_global(cx)
17854            .diagnostics
17855            .inline
17856            .max_severity
17857            .unwrap_or(self.diagnostics_max_severity);
17858
17859        if !self.inline_diagnostics_enabled()
17860            || !self.diagnostics_enabled()
17861            || !self.show_inline_diagnostics
17862            || max_severity == DiagnosticSeverity::Off
17863        {
17864            self.inline_diagnostics_update = Task::ready(());
17865            self.inline_diagnostics.clear();
17866            return;
17867        }
17868
17869        let debounce_ms = ProjectSettings::get_global(cx)
17870            .diagnostics
17871            .inline
17872            .update_debounce_ms;
17873        let debounce = if debounce && debounce_ms > 0 {
17874            Some(Duration::from_millis(debounce_ms))
17875        } else {
17876            None
17877        };
17878        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17879            if let Some(debounce) = debounce {
17880                cx.background_executor().timer(debounce).await;
17881            }
17882            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17883                editor
17884                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17885                    .ok()
17886            }) else {
17887                return;
17888            };
17889
17890            let new_inline_diagnostics = cx
17891                .background_spawn(async move {
17892                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17893                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17894                        let message = diagnostic_entry
17895                            .diagnostic
17896                            .message
17897                            .split_once('\n')
17898                            .map(|(line, _)| line)
17899                            .map(SharedString::new)
17900                            .unwrap_or_else(|| {
17901                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17902                            });
17903                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17904                        let (Ok(i) | Err(i)) = inline_diagnostics
17905                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17906                        inline_diagnostics.insert(
17907                            i,
17908                            (
17909                                start_anchor,
17910                                InlineDiagnostic {
17911                                    message,
17912                                    group_id: diagnostic_entry.diagnostic.group_id,
17913                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17914                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17915                                    severity: diagnostic_entry.diagnostic.severity,
17916                                },
17917                            ),
17918                        );
17919                    }
17920                    inline_diagnostics
17921                })
17922                .await;
17923
17924            editor
17925                .update(cx, |editor, cx| {
17926                    editor.inline_diagnostics = new_inline_diagnostics;
17927                    cx.notify();
17928                })
17929                .ok();
17930        });
17931    }
17932
17933    fn pull_diagnostics(
17934        &mut self,
17935        buffer_id: Option<BufferId>,
17936        window: &Window,
17937        cx: &mut Context<Self>,
17938    ) -> Option<()> {
17939        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
17940            return None;
17941        }
17942        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17943            .diagnostics
17944            .lsp_pull_diagnostics;
17945        if !pull_diagnostics_settings.enabled {
17946            return None;
17947        }
17948        let project = self.project()?.downgrade();
17949        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17950        let mut buffers = self.buffer.read(cx).all_buffers();
17951        buffers.retain(|buffer| {
17952            let buffer_id_to_retain = buffer.read(cx).remote_id();
17953            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17954                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17955        });
17956        if buffers.is_empty() {
17957            self.pull_diagnostics_task = Task::ready(());
17958            return None;
17959        }
17960
17961        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17962            cx.background_executor().timer(debounce).await;
17963
17964            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17965                buffers
17966                    .into_iter()
17967                    .filter_map(|buffer| {
17968                        project
17969                            .update(cx, |project, cx| {
17970                                project.lsp_store().update(cx, |lsp_store, cx| {
17971                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17972                                })
17973                            })
17974                            .ok()
17975                    })
17976                    .collect::<FuturesUnordered<_>>()
17977            }) else {
17978                return;
17979            };
17980
17981            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17982                match pull_task {
17983                    Ok(()) => {
17984                        if editor
17985                            .update_in(cx, |editor, window, cx| {
17986                                editor.update_diagnostics_state(window, cx);
17987                            })
17988                            .is_err()
17989                        {
17990                            return;
17991                        }
17992                    }
17993                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17994                }
17995            }
17996        });
17997
17998        Some(())
17999    }
18000
18001    pub fn set_selections_from_remote(
18002        &mut self,
18003        selections: Vec<Selection<Anchor>>,
18004        pending_selection: Option<Selection<Anchor>>,
18005        window: &mut Window,
18006        cx: &mut Context<Self>,
18007    ) {
18008        let old_cursor_position = self.selections.newest_anchor().head();
18009        self.selections.change_with(cx, |s| {
18010            s.select_anchors(selections);
18011            if let Some(pending_selection) = pending_selection {
18012                s.set_pending(pending_selection, SelectMode::Character);
18013            } else {
18014                s.clear_pending();
18015            }
18016        });
18017        self.selections_did_change(
18018            false,
18019            &old_cursor_position,
18020            SelectionEffects::default(),
18021            window,
18022            cx,
18023        );
18024    }
18025
18026    pub fn transact(
18027        &mut self,
18028        window: &mut Window,
18029        cx: &mut Context<Self>,
18030        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18031    ) -> Option<TransactionId> {
18032        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18033            this.start_transaction_at(Instant::now(), window, cx);
18034            update(this, window, cx);
18035            this.end_transaction_at(Instant::now(), cx)
18036        })
18037    }
18038
18039    pub fn start_transaction_at(
18040        &mut self,
18041        now: Instant,
18042        window: &mut Window,
18043        cx: &mut Context<Self>,
18044    ) -> Option<TransactionId> {
18045        self.end_selection(window, cx);
18046        if let Some(tx_id) = self
18047            .buffer
18048            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18049        {
18050            self.selection_history
18051                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18052            cx.emit(EditorEvent::TransactionBegun {
18053                transaction_id: tx_id,
18054            });
18055            Some(tx_id)
18056        } else {
18057            None
18058        }
18059    }
18060
18061    pub fn end_transaction_at(
18062        &mut self,
18063        now: Instant,
18064        cx: &mut Context<Self>,
18065    ) -> Option<TransactionId> {
18066        if let Some(transaction_id) = self
18067            .buffer
18068            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18069        {
18070            if let Some((_, end_selections)) =
18071                self.selection_history.transaction_mut(transaction_id)
18072            {
18073                *end_selections = Some(self.selections.disjoint_anchors_arc());
18074            } else {
18075                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18076            }
18077
18078            cx.emit(EditorEvent::Edited { transaction_id });
18079            Some(transaction_id)
18080        } else {
18081            None
18082        }
18083    }
18084
18085    pub fn modify_transaction_selection_history(
18086        &mut self,
18087        transaction_id: TransactionId,
18088        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18089    ) -> bool {
18090        self.selection_history
18091            .transaction_mut(transaction_id)
18092            .map(modify)
18093            .is_some()
18094    }
18095
18096    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18097        if self.selection_mark_mode {
18098            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18099                s.move_with(|_, sel| {
18100                    sel.collapse_to(sel.head(), SelectionGoal::None);
18101                });
18102            })
18103        }
18104        self.selection_mark_mode = true;
18105        cx.notify();
18106    }
18107
18108    pub fn swap_selection_ends(
18109        &mut self,
18110        _: &actions::SwapSelectionEnds,
18111        window: &mut Window,
18112        cx: &mut Context<Self>,
18113    ) {
18114        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18115            s.move_with(|_, sel| {
18116                if sel.start != sel.end {
18117                    sel.reversed = !sel.reversed
18118                }
18119            });
18120        });
18121        self.request_autoscroll(Autoscroll::newest(), cx);
18122        cx.notify();
18123    }
18124
18125    pub fn toggle_focus(
18126        workspace: &mut Workspace,
18127        _: &actions::ToggleFocus,
18128        window: &mut Window,
18129        cx: &mut Context<Workspace>,
18130    ) {
18131        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18132            return;
18133        };
18134        workspace.activate_item(&item, true, true, window, cx);
18135    }
18136
18137    pub fn toggle_fold(
18138        &mut self,
18139        _: &actions::ToggleFold,
18140        window: &mut Window,
18141        cx: &mut Context<Self>,
18142    ) {
18143        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18144            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18145            let selection = self.selections.newest::<Point>(&display_map);
18146
18147            let range = if selection.is_empty() {
18148                let point = selection.head().to_display_point(&display_map);
18149                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18150                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18151                    .to_point(&display_map);
18152                start..end
18153            } else {
18154                selection.range()
18155            };
18156            if display_map.folds_in_range(range).next().is_some() {
18157                self.unfold_lines(&Default::default(), window, cx)
18158            } else {
18159                self.fold(&Default::default(), window, cx)
18160            }
18161        } else {
18162            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18163            let buffer_ids: HashSet<_> = self
18164                .selections
18165                .disjoint_anchor_ranges()
18166                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18167                .collect();
18168
18169            let should_unfold = buffer_ids
18170                .iter()
18171                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18172
18173            for buffer_id in buffer_ids {
18174                if should_unfold {
18175                    self.unfold_buffer(buffer_id, cx);
18176                } else {
18177                    self.fold_buffer(buffer_id, cx);
18178                }
18179            }
18180        }
18181    }
18182
18183    pub fn toggle_fold_recursive(
18184        &mut self,
18185        _: &actions::ToggleFoldRecursive,
18186        window: &mut Window,
18187        cx: &mut Context<Self>,
18188    ) {
18189        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18190
18191        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18192        let range = if selection.is_empty() {
18193            let point = selection.head().to_display_point(&display_map);
18194            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18195            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18196                .to_point(&display_map);
18197            start..end
18198        } else {
18199            selection.range()
18200        };
18201        if display_map.folds_in_range(range).next().is_some() {
18202            self.unfold_recursive(&Default::default(), window, cx)
18203        } else {
18204            self.fold_recursive(&Default::default(), window, cx)
18205        }
18206    }
18207
18208    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18209        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18210            let mut to_fold = Vec::new();
18211            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18212            let selections = self.selections.all_adjusted(&display_map);
18213
18214            for selection in selections {
18215                let range = selection.range().sorted();
18216                let buffer_start_row = range.start.row;
18217
18218                if range.start.row != range.end.row {
18219                    let mut found = false;
18220                    let mut row = range.start.row;
18221                    while row <= range.end.row {
18222                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18223                        {
18224                            found = true;
18225                            row = crease.range().end.row + 1;
18226                            to_fold.push(crease);
18227                        } else {
18228                            row += 1
18229                        }
18230                    }
18231                    if found {
18232                        continue;
18233                    }
18234                }
18235
18236                for row in (0..=range.start.row).rev() {
18237                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18238                        && crease.range().end.row >= buffer_start_row
18239                    {
18240                        to_fold.push(crease);
18241                        if row <= range.start.row {
18242                            break;
18243                        }
18244                    }
18245                }
18246            }
18247
18248            self.fold_creases(to_fold, true, window, cx);
18249        } else {
18250            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18251            let buffer_ids = self
18252                .selections
18253                .disjoint_anchor_ranges()
18254                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18255                .collect::<HashSet<_>>();
18256            for buffer_id in buffer_ids {
18257                self.fold_buffer(buffer_id, cx);
18258            }
18259        }
18260    }
18261
18262    pub fn toggle_fold_all(
18263        &mut self,
18264        _: &actions::ToggleFoldAll,
18265        window: &mut Window,
18266        cx: &mut Context<Self>,
18267    ) {
18268        if self.buffer.read(cx).is_singleton() {
18269            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18270            let has_folds = display_map
18271                .folds_in_range(0..display_map.buffer_snapshot().len())
18272                .next()
18273                .is_some();
18274
18275            if has_folds {
18276                self.unfold_all(&actions::UnfoldAll, window, cx);
18277            } else {
18278                self.fold_all(&actions::FoldAll, window, cx);
18279            }
18280        } else {
18281            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18282            let should_unfold = buffer_ids
18283                .iter()
18284                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18285
18286            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18287                editor
18288                    .update_in(cx, |editor, _, cx| {
18289                        for buffer_id in buffer_ids {
18290                            if should_unfold {
18291                                editor.unfold_buffer(buffer_id, cx);
18292                            } else {
18293                                editor.fold_buffer(buffer_id, cx);
18294                            }
18295                        }
18296                    })
18297                    .ok();
18298            });
18299        }
18300    }
18301
18302    fn fold_at_level(
18303        &mut self,
18304        fold_at: &FoldAtLevel,
18305        window: &mut Window,
18306        cx: &mut Context<Self>,
18307    ) {
18308        if !self.buffer.read(cx).is_singleton() {
18309            return;
18310        }
18311
18312        let fold_at_level = fold_at.0;
18313        let snapshot = self.buffer.read(cx).snapshot(cx);
18314        let mut to_fold = Vec::new();
18315        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18316
18317        let row_ranges_to_keep: Vec<Range<u32>> = self
18318            .selections
18319            .all::<Point>(&self.display_snapshot(cx))
18320            .into_iter()
18321            .map(|sel| sel.start.row..sel.end.row)
18322            .collect();
18323
18324        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18325            while start_row < end_row {
18326                match self
18327                    .snapshot(window, cx)
18328                    .crease_for_buffer_row(MultiBufferRow(start_row))
18329                {
18330                    Some(crease) => {
18331                        let nested_start_row = crease.range().start.row + 1;
18332                        let nested_end_row = crease.range().end.row;
18333
18334                        if current_level < fold_at_level {
18335                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18336                        } else if current_level == fold_at_level {
18337                            // Fold iff there is no selection completely contained within the fold region
18338                            if !row_ranges_to_keep.iter().any(|selection| {
18339                                selection.end >= nested_start_row
18340                                    && selection.start <= nested_end_row
18341                            }) {
18342                                to_fold.push(crease);
18343                            }
18344                        }
18345
18346                        start_row = nested_end_row + 1;
18347                    }
18348                    None => start_row += 1,
18349                }
18350            }
18351        }
18352
18353        self.fold_creases(to_fold, true, window, cx);
18354    }
18355
18356    pub fn fold_at_level_1(
18357        &mut self,
18358        _: &actions::FoldAtLevel1,
18359        window: &mut Window,
18360        cx: &mut Context<Self>,
18361    ) {
18362        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18363    }
18364
18365    pub fn fold_at_level_2(
18366        &mut self,
18367        _: &actions::FoldAtLevel2,
18368        window: &mut Window,
18369        cx: &mut Context<Self>,
18370    ) {
18371        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18372    }
18373
18374    pub fn fold_at_level_3(
18375        &mut self,
18376        _: &actions::FoldAtLevel3,
18377        window: &mut Window,
18378        cx: &mut Context<Self>,
18379    ) {
18380        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18381    }
18382
18383    pub fn fold_at_level_4(
18384        &mut self,
18385        _: &actions::FoldAtLevel4,
18386        window: &mut Window,
18387        cx: &mut Context<Self>,
18388    ) {
18389        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18390    }
18391
18392    pub fn fold_at_level_5(
18393        &mut self,
18394        _: &actions::FoldAtLevel5,
18395        window: &mut Window,
18396        cx: &mut Context<Self>,
18397    ) {
18398        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18399    }
18400
18401    pub fn fold_at_level_6(
18402        &mut self,
18403        _: &actions::FoldAtLevel6,
18404        window: &mut Window,
18405        cx: &mut Context<Self>,
18406    ) {
18407        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18408    }
18409
18410    pub fn fold_at_level_7(
18411        &mut self,
18412        _: &actions::FoldAtLevel7,
18413        window: &mut Window,
18414        cx: &mut Context<Self>,
18415    ) {
18416        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18417    }
18418
18419    pub fn fold_at_level_8(
18420        &mut self,
18421        _: &actions::FoldAtLevel8,
18422        window: &mut Window,
18423        cx: &mut Context<Self>,
18424    ) {
18425        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18426    }
18427
18428    pub fn fold_at_level_9(
18429        &mut self,
18430        _: &actions::FoldAtLevel9,
18431        window: &mut Window,
18432        cx: &mut Context<Self>,
18433    ) {
18434        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18435    }
18436
18437    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18438        if self.buffer.read(cx).is_singleton() {
18439            let mut fold_ranges = Vec::new();
18440            let snapshot = self.buffer.read(cx).snapshot(cx);
18441
18442            for row in 0..snapshot.max_row().0 {
18443                if let Some(foldable_range) = self
18444                    .snapshot(window, cx)
18445                    .crease_for_buffer_row(MultiBufferRow(row))
18446                {
18447                    fold_ranges.push(foldable_range);
18448                }
18449            }
18450
18451            self.fold_creases(fold_ranges, true, window, cx);
18452        } else {
18453            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18454                editor
18455                    .update_in(cx, |editor, _, cx| {
18456                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18457                            editor.fold_buffer(buffer_id, cx);
18458                        }
18459                    })
18460                    .ok();
18461            });
18462        }
18463    }
18464
18465    pub fn fold_function_bodies(
18466        &mut self,
18467        _: &actions::FoldFunctionBodies,
18468        window: &mut Window,
18469        cx: &mut Context<Self>,
18470    ) {
18471        let snapshot = self.buffer.read(cx).snapshot(cx);
18472
18473        let ranges = snapshot
18474            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18475            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18476            .collect::<Vec<_>>();
18477
18478        let creases = ranges
18479            .into_iter()
18480            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18481            .collect();
18482
18483        self.fold_creases(creases, true, window, cx);
18484    }
18485
18486    pub fn fold_recursive(
18487        &mut self,
18488        _: &actions::FoldRecursive,
18489        window: &mut Window,
18490        cx: &mut Context<Self>,
18491    ) {
18492        let mut to_fold = Vec::new();
18493        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18494        let selections = self.selections.all_adjusted(&display_map);
18495
18496        for selection in selections {
18497            let range = selection.range().sorted();
18498            let buffer_start_row = range.start.row;
18499
18500            if range.start.row != range.end.row {
18501                let mut found = false;
18502                for row in range.start.row..=range.end.row {
18503                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18504                        found = true;
18505                        to_fold.push(crease);
18506                    }
18507                }
18508                if found {
18509                    continue;
18510                }
18511            }
18512
18513            for row in (0..=range.start.row).rev() {
18514                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18515                    if crease.range().end.row >= buffer_start_row {
18516                        to_fold.push(crease);
18517                    } else {
18518                        break;
18519                    }
18520                }
18521            }
18522        }
18523
18524        self.fold_creases(to_fold, true, window, cx);
18525    }
18526
18527    pub fn fold_at(
18528        &mut self,
18529        buffer_row: MultiBufferRow,
18530        window: &mut Window,
18531        cx: &mut Context<Self>,
18532    ) {
18533        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18534
18535        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18536            let autoscroll = self
18537                .selections
18538                .all::<Point>(&display_map)
18539                .iter()
18540                .any(|selection| crease.range().overlaps(&selection.range()));
18541
18542            self.fold_creases(vec![crease], autoscroll, window, cx);
18543        }
18544    }
18545
18546    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18547        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18548            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18549            let buffer = display_map.buffer_snapshot();
18550            let selections = self.selections.all::<Point>(&display_map);
18551            let ranges = selections
18552                .iter()
18553                .map(|s| {
18554                    let range = s.display_range(&display_map).sorted();
18555                    let mut start = range.start.to_point(&display_map);
18556                    let mut end = range.end.to_point(&display_map);
18557                    start.column = 0;
18558                    end.column = buffer.line_len(MultiBufferRow(end.row));
18559                    start..end
18560                })
18561                .collect::<Vec<_>>();
18562
18563            self.unfold_ranges(&ranges, true, true, cx);
18564        } else {
18565            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18566            let buffer_ids = self
18567                .selections
18568                .disjoint_anchor_ranges()
18569                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18570                .collect::<HashSet<_>>();
18571            for buffer_id in buffer_ids {
18572                self.unfold_buffer(buffer_id, cx);
18573            }
18574        }
18575    }
18576
18577    pub fn unfold_recursive(
18578        &mut self,
18579        _: &UnfoldRecursive,
18580        _window: &mut Window,
18581        cx: &mut Context<Self>,
18582    ) {
18583        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18584        let selections = self.selections.all::<Point>(&display_map);
18585        let ranges = selections
18586            .iter()
18587            .map(|s| {
18588                let mut range = s.display_range(&display_map).sorted();
18589                *range.start.column_mut() = 0;
18590                *range.end.column_mut() = display_map.line_len(range.end.row());
18591                let start = range.start.to_point(&display_map);
18592                let end = range.end.to_point(&display_map);
18593                start..end
18594            })
18595            .collect::<Vec<_>>();
18596
18597        self.unfold_ranges(&ranges, true, true, cx);
18598    }
18599
18600    pub fn unfold_at(
18601        &mut self,
18602        buffer_row: MultiBufferRow,
18603        _window: &mut Window,
18604        cx: &mut Context<Self>,
18605    ) {
18606        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18607
18608        let intersection_range = Point::new(buffer_row.0, 0)
18609            ..Point::new(
18610                buffer_row.0,
18611                display_map.buffer_snapshot().line_len(buffer_row),
18612            );
18613
18614        let autoscroll = self
18615            .selections
18616            .all::<Point>(&display_map)
18617            .iter()
18618            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18619
18620        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18621    }
18622
18623    pub fn unfold_all(
18624        &mut self,
18625        _: &actions::UnfoldAll,
18626        _window: &mut Window,
18627        cx: &mut Context<Self>,
18628    ) {
18629        if self.buffer.read(cx).is_singleton() {
18630            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18631            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18632        } else {
18633            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18634                editor
18635                    .update(cx, |editor, cx| {
18636                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18637                            editor.unfold_buffer(buffer_id, cx);
18638                        }
18639                    })
18640                    .ok();
18641            });
18642        }
18643    }
18644
18645    pub fn fold_selected_ranges(
18646        &mut self,
18647        _: &FoldSelectedRanges,
18648        window: &mut Window,
18649        cx: &mut Context<Self>,
18650    ) {
18651        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18652        let selections = self.selections.all_adjusted(&display_map);
18653        let ranges = selections
18654            .into_iter()
18655            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18656            .collect::<Vec<_>>();
18657        self.fold_creases(ranges, true, window, cx);
18658    }
18659
18660    pub fn fold_ranges<T: ToOffset + Clone>(
18661        &mut self,
18662        ranges: Vec<Range<T>>,
18663        auto_scroll: bool,
18664        window: &mut Window,
18665        cx: &mut Context<Self>,
18666    ) {
18667        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18668        let ranges = ranges
18669            .into_iter()
18670            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18671            .collect::<Vec<_>>();
18672        self.fold_creases(ranges, auto_scroll, window, cx);
18673    }
18674
18675    pub fn fold_creases<T: ToOffset + Clone>(
18676        &mut self,
18677        creases: Vec<Crease<T>>,
18678        auto_scroll: bool,
18679        _window: &mut Window,
18680        cx: &mut Context<Self>,
18681    ) {
18682        if creases.is_empty() {
18683            return;
18684        }
18685
18686        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18687
18688        if auto_scroll {
18689            self.request_autoscroll(Autoscroll::fit(), cx);
18690        }
18691
18692        cx.notify();
18693
18694        self.scrollbar_marker_state.dirty = true;
18695        self.folds_did_change(cx);
18696    }
18697
18698    /// Removes any folds whose ranges intersect any of the given ranges.
18699    pub fn unfold_ranges<T: ToOffset + Clone>(
18700        &mut self,
18701        ranges: &[Range<T>],
18702        inclusive: bool,
18703        auto_scroll: bool,
18704        cx: &mut Context<Self>,
18705    ) {
18706        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18707            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18708        });
18709        self.folds_did_change(cx);
18710    }
18711
18712    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18713        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18714            return;
18715        }
18716        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18717        self.display_map.update(cx, |display_map, cx| {
18718            display_map.fold_buffers([buffer_id], cx)
18719        });
18720        cx.emit(EditorEvent::BufferFoldToggled {
18721            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18722            folded: true,
18723        });
18724        cx.notify();
18725    }
18726
18727    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18728        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18729            return;
18730        }
18731        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18732        self.display_map.update(cx, |display_map, cx| {
18733            display_map.unfold_buffers([buffer_id], cx);
18734        });
18735        cx.emit(EditorEvent::BufferFoldToggled {
18736            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18737            folded: false,
18738        });
18739        cx.notify();
18740    }
18741
18742    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18743        self.display_map.read(cx).is_buffer_folded(buffer)
18744    }
18745
18746    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18747        self.display_map.read(cx).folded_buffers()
18748    }
18749
18750    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18751        self.display_map.update(cx, |display_map, cx| {
18752            display_map.disable_header_for_buffer(buffer_id, cx);
18753        });
18754        cx.notify();
18755    }
18756
18757    /// Removes any folds with the given ranges.
18758    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18759        &mut self,
18760        ranges: &[Range<T>],
18761        type_id: TypeId,
18762        auto_scroll: bool,
18763        cx: &mut Context<Self>,
18764    ) {
18765        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18766            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18767        });
18768        self.folds_did_change(cx);
18769    }
18770
18771    fn remove_folds_with<T: ToOffset + Clone>(
18772        &mut self,
18773        ranges: &[Range<T>],
18774        auto_scroll: bool,
18775        cx: &mut Context<Self>,
18776        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18777    ) {
18778        if ranges.is_empty() {
18779            return;
18780        }
18781
18782        let mut buffers_affected = HashSet::default();
18783        let multi_buffer = self.buffer().read(cx);
18784        for range in ranges {
18785            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18786                buffers_affected.insert(buffer.read(cx).remote_id());
18787            };
18788        }
18789
18790        self.display_map.update(cx, update);
18791
18792        if auto_scroll {
18793            self.request_autoscroll(Autoscroll::fit(), cx);
18794        }
18795
18796        cx.notify();
18797        self.scrollbar_marker_state.dirty = true;
18798        self.active_indent_guides_state.dirty = true;
18799    }
18800
18801    pub fn update_renderer_widths(
18802        &mut self,
18803        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18804        cx: &mut Context<Self>,
18805    ) -> bool {
18806        self.display_map
18807            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18808    }
18809
18810    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18811        self.display_map.read(cx).fold_placeholder.clone()
18812    }
18813
18814    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18815        self.buffer.update(cx, |buffer, cx| {
18816            buffer.set_all_diff_hunks_expanded(cx);
18817        });
18818    }
18819
18820    pub fn expand_all_diff_hunks(
18821        &mut self,
18822        _: &ExpandAllDiffHunks,
18823        _window: &mut Window,
18824        cx: &mut Context<Self>,
18825    ) {
18826        self.buffer.update(cx, |buffer, cx| {
18827            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18828        });
18829    }
18830
18831    pub fn collapse_all_diff_hunks(
18832        &mut self,
18833        _: &CollapseAllDiffHunks,
18834        _window: &mut Window,
18835        cx: &mut Context<Self>,
18836    ) {
18837        self.buffer.update(cx, |buffer, cx| {
18838            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18839        });
18840    }
18841
18842    pub fn toggle_selected_diff_hunks(
18843        &mut self,
18844        _: &ToggleSelectedDiffHunks,
18845        _window: &mut Window,
18846        cx: &mut Context<Self>,
18847    ) {
18848        let ranges: Vec<_> = self
18849            .selections
18850            .disjoint_anchors()
18851            .iter()
18852            .map(|s| s.range())
18853            .collect();
18854        self.toggle_diff_hunks_in_ranges(ranges, cx);
18855    }
18856
18857    pub fn diff_hunks_in_ranges<'a>(
18858        &'a self,
18859        ranges: &'a [Range<Anchor>],
18860        buffer: &'a MultiBufferSnapshot,
18861    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18862        ranges.iter().flat_map(move |range| {
18863            let end_excerpt_id = range.end.excerpt_id;
18864            let range = range.to_point(buffer);
18865            let mut peek_end = range.end;
18866            if range.end.row < buffer.max_row().0 {
18867                peek_end = Point::new(range.end.row + 1, 0);
18868            }
18869            buffer
18870                .diff_hunks_in_range(range.start..peek_end)
18871                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18872        })
18873    }
18874
18875    pub fn has_stageable_diff_hunks_in_ranges(
18876        &self,
18877        ranges: &[Range<Anchor>],
18878        snapshot: &MultiBufferSnapshot,
18879    ) -> bool {
18880        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18881        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18882    }
18883
18884    pub fn toggle_staged_selected_diff_hunks(
18885        &mut self,
18886        _: &::git::ToggleStaged,
18887        _: &mut Window,
18888        cx: &mut Context<Self>,
18889    ) {
18890        let snapshot = self.buffer.read(cx).snapshot(cx);
18891        let ranges: Vec<_> = self
18892            .selections
18893            .disjoint_anchors()
18894            .iter()
18895            .map(|s| s.range())
18896            .collect();
18897        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18898        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18899    }
18900
18901    pub fn set_render_diff_hunk_controls(
18902        &mut self,
18903        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18904        cx: &mut Context<Self>,
18905    ) {
18906        self.render_diff_hunk_controls = render_diff_hunk_controls;
18907        cx.notify();
18908    }
18909
18910    pub fn stage_and_next(
18911        &mut self,
18912        _: &::git::StageAndNext,
18913        window: &mut Window,
18914        cx: &mut Context<Self>,
18915    ) {
18916        self.do_stage_or_unstage_and_next(true, window, cx);
18917    }
18918
18919    pub fn unstage_and_next(
18920        &mut self,
18921        _: &::git::UnstageAndNext,
18922        window: &mut Window,
18923        cx: &mut Context<Self>,
18924    ) {
18925        self.do_stage_or_unstage_and_next(false, window, cx);
18926    }
18927
18928    pub fn stage_or_unstage_diff_hunks(
18929        &mut self,
18930        stage: bool,
18931        ranges: Vec<Range<Anchor>>,
18932        cx: &mut Context<Self>,
18933    ) {
18934        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18935        cx.spawn(async move |this, cx| {
18936            task.await?;
18937            this.update(cx, |this, cx| {
18938                let snapshot = this.buffer.read(cx).snapshot(cx);
18939                let chunk_by = this
18940                    .diff_hunks_in_ranges(&ranges, &snapshot)
18941                    .chunk_by(|hunk| hunk.buffer_id);
18942                for (buffer_id, hunks) in &chunk_by {
18943                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18944                }
18945            })
18946        })
18947        .detach_and_log_err(cx);
18948    }
18949
18950    fn save_buffers_for_ranges_if_needed(
18951        &mut self,
18952        ranges: &[Range<Anchor>],
18953        cx: &mut Context<Editor>,
18954    ) -> Task<Result<()>> {
18955        let multibuffer = self.buffer.read(cx);
18956        let snapshot = multibuffer.read(cx);
18957        let buffer_ids: HashSet<_> = ranges
18958            .iter()
18959            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18960            .collect();
18961        drop(snapshot);
18962
18963        let mut buffers = HashSet::default();
18964        for buffer_id in buffer_ids {
18965            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18966                let buffer = buffer_entity.read(cx);
18967                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18968                {
18969                    buffers.insert(buffer_entity);
18970                }
18971            }
18972        }
18973
18974        if let Some(project) = &self.project {
18975            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18976        } else {
18977            Task::ready(Ok(()))
18978        }
18979    }
18980
18981    fn do_stage_or_unstage_and_next(
18982        &mut self,
18983        stage: bool,
18984        window: &mut Window,
18985        cx: &mut Context<Self>,
18986    ) {
18987        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18988
18989        if ranges.iter().any(|range| range.start != range.end) {
18990            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18991            return;
18992        }
18993
18994        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18995        let snapshot = self.snapshot(window, cx);
18996        let position = self
18997            .selections
18998            .newest::<Point>(&snapshot.display_snapshot)
18999            .head();
19000        let mut row = snapshot
19001            .buffer_snapshot()
19002            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19003            .find(|hunk| hunk.row_range.start.0 > position.row)
19004            .map(|hunk| hunk.row_range.start);
19005
19006        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19007        // Outside of the project diff editor, wrap around to the beginning.
19008        if !all_diff_hunks_expanded {
19009            row = row.or_else(|| {
19010                snapshot
19011                    .buffer_snapshot()
19012                    .diff_hunks_in_range(Point::zero()..position)
19013                    .find(|hunk| hunk.row_range.end.0 < position.row)
19014                    .map(|hunk| hunk.row_range.start)
19015            });
19016        }
19017
19018        if let Some(row) = row {
19019            let destination = Point::new(row.0, 0);
19020            let autoscroll = Autoscroll::center();
19021
19022            self.unfold_ranges(&[destination..destination], false, false, cx);
19023            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19024                s.select_ranges([destination..destination]);
19025            });
19026        }
19027    }
19028
19029    fn do_stage_or_unstage(
19030        &self,
19031        stage: bool,
19032        buffer_id: BufferId,
19033        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19034        cx: &mut App,
19035    ) -> Option<()> {
19036        let project = self.project()?;
19037        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19038        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19039        let buffer_snapshot = buffer.read(cx).snapshot();
19040        let file_exists = buffer_snapshot
19041            .file()
19042            .is_some_and(|file| file.disk_state().exists());
19043        diff.update(cx, |diff, cx| {
19044            diff.stage_or_unstage_hunks(
19045                stage,
19046                &hunks
19047                    .map(|hunk| buffer_diff::DiffHunk {
19048                        buffer_range: hunk.buffer_range,
19049                        diff_base_byte_range: hunk.diff_base_byte_range,
19050                        secondary_status: hunk.secondary_status,
19051                        range: Point::zero()..Point::zero(), // unused
19052                    })
19053                    .collect::<Vec<_>>(),
19054                &buffer_snapshot,
19055                file_exists,
19056                cx,
19057            )
19058        });
19059        None
19060    }
19061
19062    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19063        let ranges: Vec<_> = self
19064            .selections
19065            .disjoint_anchors()
19066            .iter()
19067            .map(|s| s.range())
19068            .collect();
19069        self.buffer
19070            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19071    }
19072
19073    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19074        self.buffer.update(cx, |buffer, cx| {
19075            let ranges = vec![Anchor::min()..Anchor::max()];
19076            if !buffer.all_diff_hunks_expanded()
19077                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19078            {
19079                buffer.collapse_diff_hunks(ranges, cx);
19080                true
19081            } else {
19082                false
19083            }
19084        })
19085    }
19086
19087    fn toggle_diff_hunks_in_ranges(
19088        &mut self,
19089        ranges: Vec<Range<Anchor>>,
19090        cx: &mut Context<Editor>,
19091    ) {
19092        self.buffer.update(cx, |buffer, cx| {
19093            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19094            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19095        })
19096    }
19097
19098    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19099        self.buffer.update(cx, |buffer, cx| {
19100            let snapshot = buffer.snapshot(cx);
19101            let excerpt_id = range.end.excerpt_id;
19102            let point_range = range.to_point(&snapshot);
19103            let expand = !buffer.single_hunk_is_expanded(range, cx);
19104            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19105        })
19106    }
19107
19108    pub(crate) fn apply_all_diff_hunks(
19109        &mut self,
19110        _: &ApplyAllDiffHunks,
19111        window: &mut Window,
19112        cx: &mut Context<Self>,
19113    ) {
19114        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19115
19116        let buffers = self.buffer.read(cx).all_buffers();
19117        for branch_buffer in buffers {
19118            branch_buffer.update(cx, |branch_buffer, cx| {
19119                branch_buffer.merge_into_base(Vec::new(), cx);
19120            });
19121        }
19122
19123        if let Some(project) = self.project.clone() {
19124            self.save(
19125                SaveOptions {
19126                    format: true,
19127                    autosave: false,
19128                },
19129                project,
19130                window,
19131                cx,
19132            )
19133            .detach_and_log_err(cx);
19134        }
19135    }
19136
19137    pub(crate) fn apply_selected_diff_hunks(
19138        &mut self,
19139        _: &ApplyDiffHunk,
19140        window: &mut Window,
19141        cx: &mut Context<Self>,
19142    ) {
19143        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19144        let snapshot = self.snapshot(window, cx);
19145        let hunks = snapshot.hunks_for_ranges(
19146            self.selections
19147                .all(&snapshot.display_snapshot)
19148                .into_iter()
19149                .map(|selection| selection.range()),
19150        );
19151        let mut ranges_by_buffer = HashMap::default();
19152        self.transact(window, cx, |editor, _window, cx| {
19153            for hunk in hunks {
19154                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19155                    ranges_by_buffer
19156                        .entry(buffer.clone())
19157                        .or_insert_with(Vec::new)
19158                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19159                }
19160            }
19161
19162            for (buffer, ranges) in ranges_by_buffer {
19163                buffer.update(cx, |buffer, cx| {
19164                    buffer.merge_into_base(ranges, cx);
19165                });
19166            }
19167        });
19168
19169        if let Some(project) = self.project.clone() {
19170            self.save(
19171                SaveOptions {
19172                    format: true,
19173                    autosave: false,
19174                },
19175                project,
19176                window,
19177                cx,
19178            )
19179            .detach_and_log_err(cx);
19180        }
19181    }
19182
19183    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19184        if hovered != self.gutter_hovered {
19185            self.gutter_hovered = hovered;
19186            cx.notify();
19187        }
19188    }
19189
19190    pub fn insert_blocks(
19191        &mut self,
19192        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19193        autoscroll: Option<Autoscroll>,
19194        cx: &mut Context<Self>,
19195    ) -> Vec<CustomBlockId> {
19196        let blocks = self
19197            .display_map
19198            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19199        if let Some(autoscroll) = autoscroll {
19200            self.request_autoscroll(autoscroll, cx);
19201        }
19202        cx.notify();
19203        blocks
19204    }
19205
19206    pub fn resize_blocks(
19207        &mut self,
19208        heights: HashMap<CustomBlockId, u32>,
19209        autoscroll: Option<Autoscroll>,
19210        cx: &mut Context<Self>,
19211    ) {
19212        self.display_map
19213            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19214        if let Some(autoscroll) = autoscroll {
19215            self.request_autoscroll(autoscroll, cx);
19216        }
19217        cx.notify();
19218    }
19219
19220    pub fn replace_blocks(
19221        &mut self,
19222        renderers: HashMap<CustomBlockId, RenderBlock>,
19223        autoscroll: Option<Autoscroll>,
19224        cx: &mut Context<Self>,
19225    ) {
19226        self.display_map
19227            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19228        if let Some(autoscroll) = autoscroll {
19229            self.request_autoscroll(autoscroll, cx);
19230        }
19231        cx.notify();
19232    }
19233
19234    pub fn remove_blocks(
19235        &mut self,
19236        block_ids: HashSet<CustomBlockId>,
19237        autoscroll: Option<Autoscroll>,
19238        cx: &mut Context<Self>,
19239    ) {
19240        self.display_map.update(cx, |display_map, cx| {
19241            display_map.remove_blocks(block_ids, cx)
19242        });
19243        if let Some(autoscroll) = autoscroll {
19244            self.request_autoscroll(autoscroll, cx);
19245        }
19246        cx.notify();
19247    }
19248
19249    pub fn row_for_block(
19250        &self,
19251        block_id: CustomBlockId,
19252        cx: &mut Context<Self>,
19253    ) -> Option<DisplayRow> {
19254        self.display_map
19255            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19256    }
19257
19258    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19259        self.focused_block = Some(focused_block);
19260    }
19261
19262    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19263        self.focused_block.take()
19264    }
19265
19266    pub fn insert_creases(
19267        &mut self,
19268        creases: impl IntoIterator<Item = Crease<Anchor>>,
19269        cx: &mut Context<Self>,
19270    ) -> Vec<CreaseId> {
19271        self.display_map
19272            .update(cx, |map, cx| map.insert_creases(creases, cx))
19273    }
19274
19275    pub fn remove_creases(
19276        &mut self,
19277        ids: impl IntoIterator<Item = CreaseId>,
19278        cx: &mut Context<Self>,
19279    ) -> Vec<(CreaseId, Range<Anchor>)> {
19280        self.display_map
19281            .update(cx, |map, cx| map.remove_creases(ids, cx))
19282    }
19283
19284    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19285        self.display_map
19286            .update(cx, |map, cx| map.snapshot(cx))
19287            .longest_row()
19288    }
19289
19290    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19291        self.display_map
19292            .update(cx, |map, cx| map.snapshot(cx))
19293            .max_point()
19294    }
19295
19296    pub fn text(&self, cx: &App) -> String {
19297        self.buffer.read(cx).read(cx).text()
19298    }
19299
19300    pub fn is_empty(&self, cx: &App) -> bool {
19301        self.buffer.read(cx).read(cx).is_empty()
19302    }
19303
19304    pub fn text_option(&self, cx: &App) -> Option<String> {
19305        let text = self.text(cx);
19306        let text = text.trim();
19307
19308        if text.is_empty() {
19309            return None;
19310        }
19311
19312        Some(text.to_string())
19313    }
19314
19315    pub fn set_text(
19316        &mut self,
19317        text: impl Into<Arc<str>>,
19318        window: &mut Window,
19319        cx: &mut Context<Self>,
19320    ) {
19321        self.transact(window, cx, |this, _, cx| {
19322            this.buffer
19323                .read(cx)
19324                .as_singleton()
19325                .expect("you can only call set_text on editors for singleton buffers")
19326                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19327        });
19328    }
19329
19330    pub fn display_text(&self, cx: &mut App) -> String {
19331        self.display_map
19332            .update(cx, |map, cx| map.snapshot(cx))
19333            .text()
19334    }
19335
19336    fn create_minimap(
19337        &self,
19338        minimap_settings: MinimapSettings,
19339        window: &mut Window,
19340        cx: &mut Context<Self>,
19341    ) -> Option<Entity<Self>> {
19342        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19343            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19344    }
19345
19346    fn initialize_new_minimap(
19347        &self,
19348        minimap_settings: MinimapSettings,
19349        window: &mut Window,
19350        cx: &mut Context<Self>,
19351    ) -> Entity<Self> {
19352        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19353
19354        let mut minimap = Editor::new_internal(
19355            EditorMode::Minimap {
19356                parent: cx.weak_entity(),
19357            },
19358            self.buffer.clone(),
19359            None,
19360            Some(self.display_map.clone()),
19361            window,
19362            cx,
19363        );
19364        minimap.scroll_manager.clone_state(&self.scroll_manager);
19365        minimap.set_text_style_refinement(TextStyleRefinement {
19366            font_size: Some(MINIMAP_FONT_SIZE),
19367            font_weight: Some(MINIMAP_FONT_WEIGHT),
19368            ..Default::default()
19369        });
19370        minimap.update_minimap_configuration(minimap_settings, cx);
19371        cx.new(|_| minimap)
19372    }
19373
19374    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19375        let current_line_highlight = minimap_settings
19376            .current_line_highlight
19377            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19378        self.set_current_line_highlight(Some(current_line_highlight));
19379    }
19380
19381    pub fn minimap(&self) -> Option<&Entity<Self>> {
19382        self.minimap
19383            .as_ref()
19384            .filter(|_| self.minimap_visibility.visible())
19385    }
19386
19387    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19388        let mut wrap_guides = smallvec![];
19389
19390        if self.show_wrap_guides == Some(false) {
19391            return wrap_guides;
19392        }
19393
19394        let settings = self.buffer.read(cx).language_settings(cx);
19395        if settings.show_wrap_guides {
19396            match self.soft_wrap_mode(cx) {
19397                SoftWrap::Column(soft_wrap) => {
19398                    wrap_guides.push((soft_wrap as usize, true));
19399                }
19400                SoftWrap::Bounded(soft_wrap) => {
19401                    wrap_guides.push((soft_wrap as usize, true));
19402                }
19403                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19404            }
19405            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19406        }
19407
19408        wrap_guides
19409    }
19410
19411    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19412        let settings = self.buffer.read(cx).language_settings(cx);
19413        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19414        match mode {
19415            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19416                SoftWrap::None
19417            }
19418            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19419            language_settings::SoftWrap::PreferredLineLength => {
19420                SoftWrap::Column(settings.preferred_line_length)
19421            }
19422            language_settings::SoftWrap::Bounded => {
19423                SoftWrap::Bounded(settings.preferred_line_length)
19424            }
19425        }
19426    }
19427
19428    pub fn set_soft_wrap_mode(
19429        &mut self,
19430        mode: language_settings::SoftWrap,
19431
19432        cx: &mut Context<Self>,
19433    ) {
19434        self.soft_wrap_mode_override = Some(mode);
19435        cx.notify();
19436    }
19437
19438    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19439        self.hard_wrap = hard_wrap;
19440        cx.notify();
19441    }
19442
19443    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19444        self.text_style_refinement = Some(style);
19445    }
19446
19447    /// called by the Element so we know what style we were most recently rendered with.
19448    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19449        // We intentionally do not inform the display map about the minimap style
19450        // so that wrapping is not recalculated and stays consistent for the editor
19451        // and its linked minimap.
19452        if !self.mode.is_minimap() {
19453            let font = style.text.font();
19454            let font_size = style.text.font_size.to_pixels(window.rem_size());
19455            let display_map = self
19456                .placeholder_display_map
19457                .as_ref()
19458                .filter(|_| self.is_empty(cx))
19459                .unwrap_or(&self.display_map);
19460
19461            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19462        }
19463        self.style = Some(style);
19464    }
19465
19466    pub fn style(&self) -> Option<&EditorStyle> {
19467        self.style.as_ref()
19468    }
19469
19470    // Called by the element. This method is not designed to be called outside of the editor
19471    // element's layout code because it does not notify when rewrapping is computed synchronously.
19472    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19473        if self.is_empty(cx) {
19474            self.placeholder_display_map
19475                .as_ref()
19476                .map_or(false, |display_map| {
19477                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19478                })
19479        } else {
19480            self.display_map
19481                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19482        }
19483    }
19484
19485    pub fn set_soft_wrap(&mut self) {
19486        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19487    }
19488
19489    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19490        if self.soft_wrap_mode_override.is_some() {
19491            self.soft_wrap_mode_override.take();
19492        } else {
19493            let soft_wrap = match self.soft_wrap_mode(cx) {
19494                SoftWrap::GitDiff => return,
19495                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19496                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19497                    language_settings::SoftWrap::None
19498                }
19499            };
19500            self.soft_wrap_mode_override = Some(soft_wrap);
19501        }
19502        cx.notify();
19503    }
19504
19505    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19506        let Some(workspace) = self.workspace() else {
19507            return;
19508        };
19509        let fs = workspace.read(cx).app_state().fs.clone();
19510        let current_show = TabBarSettings::get_global(cx).show;
19511        update_settings_file(fs, cx, move |setting, _| {
19512            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19513        });
19514    }
19515
19516    pub fn toggle_indent_guides(
19517        &mut self,
19518        _: &ToggleIndentGuides,
19519        _: &mut Window,
19520        cx: &mut Context<Self>,
19521    ) {
19522        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19523            self.buffer
19524                .read(cx)
19525                .language_settings(cx)
19526                .indent_guides
19527                .enabled
19528        });
19529        self.show_indent_guides = Some(!currently_enabled);
19530        cx.notify();
19531    }
19532
19533    fn should_show_indent_guides(&self) -> Option<bool> {
19534        self.show_indent_guides
19535    }
19536
19537    pub fn toggle_line_numbers(
19538        &mut self,
19539        _: &ToggleLineNumbers,
19540        _: &mut Window,
19541        cx: &mut Context<Self>,
19542    ) {
19543        let mut editor_settings = EditorSettings::get_global(cx).clone();
19544        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19545        EditorSettings::override_global(editor_settings, cx);
19546    }
19547
19548    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19549        if let Some(show_line_numbers) = self.show_line_numbers {
19550            return show_line_numbers;
19551        }
19552        EditorSettings::get_global(cx).gutter.line_numbers
19553    }
19554
19555    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19556        match (
19557            self.use_relative_line_numbers,
19558            EditorSettings::get_global(cx).relative_line_numbers,
19559        ) {
19560            (None, setting) => setting,
19561            (Some(false), _) => RelativeLineNumbers::Disabled,
19562            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19563            (Some(true), _) => RelativeLineNumbers::Enabled,
19564        }
19565    }
19566
19567    pub fn toggle_relative_line_numbers(
19568        &mut self,
19569        _: &ToggleRelativeLineNumbers,
19570        _: &mut Window,
19571        cx: &mut Context<Self>,
19572    ) {
19573        let is_relative = self.relative_line_numbers(cx);
19574        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19575    }
19576
19577    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19578        self.use_relative_line_numbers = is_relative;
19579        cx.notify();
19580    }
19581
19582    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19583        self.show_gutter = show_gutter;
19584        cx.notify();
19585    }
19586
19587    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19588        self.show_scrollbars = ScrollbarAxes {
19589            horizontal: show,
19590            vertical: show,
19591        };
19592        cx.notify();
19593    }
19594
19595    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19596        self.show_scrollbars.vertical = show;
19597        cx.notify();
19598    }
19599
19600    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19601        self.show_scrollbars.horizontal = show;
19602        cx.notify();
19603    }
19604
19605    pub fn set_minimap_visibility(
19606        &mut self,
19607        minimap_visibility: MinimapVisibility,
19608        window: &mut Window,
19609        cx: &mut Context<Self>,
19610    ) {
19611        if self.minimap_visibility != minimap_visibility {
19612            if minimap_visibility.visible() && self.minimap.is_none() {
19613                let minimap_settings = EditorSettings::get_global(cx).minimap;
19614                self.minimap =
19615                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19616            }
19617            self.minimap_visibility = minimap_visibility;
19618            cx.notify();
19619        }
19620    }
19621
19622    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19623        self.set_show_scrollbars(false, cx);
19624        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19625    }
19626
19627    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19628        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19629    }
19630
19631    /// Normally the text in full mode and auto height editors is padded on the
19632    /// left side by roughly half a character width for improved hit testing.
19633    ///
19634    /// Use this method to disable this for cases where this is not wanted (e.g.
19635    /// if you want to align the editor text with some other text above or below)
19636    /// or if you want to add this padding to single-line editors.
19637    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19638        self.offset_content = offset_content;
19639        cx.notify();
19640    }
19641
19642    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19643        self.show_line_numbers = Some(show_line_numbers);
19644        cx.notify();
19645    }
19646
19647    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19648        self.disable_expand_excerpt_buttons = true;
19649        cx.notify();
19650    }
19651
19652    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19653        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19654        cx.notify();
19655    }
19656
19657    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19658        self.show_code_actions = Some(show_code_actions);
19659        cx.notify();
19660    }
19661
19662    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19663        self.show_runnables = Some(show_runnables);
19664        cx.notify();
19665    }
19666
19667    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19668        self.show_breakpoints = Some(show_breakpoints);
19669        cx.notify();
19670    }
19671
19672    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19673        if self.display_map.read(cx).masked != masked {
19674            self.display_map.update(cx, |map, _| map.masked = masked);
19675        }
19676        cx.notify()
19677    }
19678
19679    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19680        self.show_wrap_guides = Some(show_wrap_guides);
19681        cx.notify();
19682    }
19683
19684    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19685        self.show_indent_guides = Some(show_indent_guides);
19686        cx.notify();
19687    }
19688
19689    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19690        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19691            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19692                && let Some(dir) = file.abs_path(cx).parent()
19693            {
19694                return Some(dir.to_owned());
19695            }
19696        }
19697
19698        None
19699    }
19700
19701    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19702        self.active_excerpt(cx)?
19703            .1
19704            .read(cx)
19705            .file()
19706            .and_then(|f| f.as_local())
19707    }
19708
19709    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19710        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19711            let buffer = buffer.read(cx);
19712            if let Some(project_path) = buffer.project_path(cx) {
19713                let project = self.project()?.read(cx);
19714                project.absolute_path(&project_path, cx)
19715            } else {
19716                buffer
19717                    .file()
19718                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19719            }
19720        })
19721    }
19722
19723    pub fn reveal_in_finder(
19724        &mut self,
19725        _: &RevealInFileManager,
19726        _window: &mut Window,
19727        cx: &mut Context<Self>,
19728    ) {
19729        if let Some(target) = self.target_file(cx) {
19730            cx.reveal_path(&target.abs_path(cx));
19731        }
19732    }
19733
19734    pub fn copy_path(
19735        &mut self,
19736        _: &zed_actions::workspace::CopyPath,
19737        _window: &mut Window,
19738        cx: &mut Context<Self>,
19739    ) {
19740        if let Some(path) = self.target_file_abs_path(cx)
19741            && let Some(path) = path.to_str()
19742        {
19743            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19744        } else {
19745            cx.propagate();
19746        }
19747    }
19748
19749    pub fn copy_relative_path(
19750        &mut self,
19751        _: &zed_actions::workspace::CopyRelativePath,
19752        _window: &mut Window,
19753        cx: &mut Context<Self>,
19754    ) {
19755        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19756            let project = self.project()?.read(cx);
19757            let path = buffer.read(cx).file()?.path();
19758            let path = path.display(project.path_style(cx));
19759            Some(path)
19760        }) {
19761            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19762        } else {
19763            cx.propagate();
19764        }
19765    }
19766
19767    /// Returns the project path for the editor's buffer, if any buffer is
19768    /// opened in the editor.
19769    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19770        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19771            buffer.read(cx).project_path(cx)
19772        } else {
19773            None
19774        }
19775    }
19776
19777    // Returns true if the editor handled a go-to-line request
19778    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19779        maybe!({
19780            let breakpoint_store = self.breakpoint_store.as_ref()?;
19781
19782            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19783            else {
19784                self.clear_row_highlights::<ActiveDebugLine>();
19785                return None;
19786            };
19787
19788            let position = active_stack_frame.position;
19789            let buffer_id = position.buffer_id?;
19790            let snapshot = self
19791                .project
19792                .as_ref()?
19793                .read(cx)
19794                .buffer_for_id(buffer_id, cx)?
19795                .read(cx)
19796                .snapshot();
19797
19798            let mut handled = false;
19799            for (id, ExcerptRange { context, .. }) in
19800                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19801            {
19802                if context.start.cmp(&position, &snapshot).is_ge()
19803                    || context.end.cmp(&position, &snapshot).is_lt()
19804                {
19805                    continue;
19806                }
19807                let snapshot = self.buffer.read(cx).snapshot(cx);
19808                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19809
19810                handled = true;
19811                self.clear_row_highlights::<ActiveDebugLine>();
19812
19813                self.go_to_line::<ActiveDebugLine>(
19814                    multibuffer_anchor,
19815                    Some(cx.theme().colors().editor_debugger_active_line_background),
19816                    window,
19817                    cx,
19818                );
19819
19820                cx.notify();
19821            }
19822
19823            handled.then_some(())
19824        })
19825        .is_some()
19826    }
19827
19828    pub fn copy_file_name_without_extension(
19829        &mut self,
19830        _: &CopyFileNameWithoutExtension,
19831        _: &mut Window,
19832        cx: &mut Context<Self>,
19833    ) {
19834        if let Some(file) = self.target_file(cx)
19835            && let Some(file_stem) = file.path().file_stem()
19836        {
19837            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19838        }
19839    }
19840
19841    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19842        if let Some(file) = self.target_file(cx)
19843            && let Some(name) = file.path().file_name()
19844        {
19845            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19846        }
19847    }
19848
19849    pub fn toggle_git_blame(
19850        &mut self,
19851        _: &::git::Blame,
19852        window: &mut Window,
19853        cx: &mut Context<Self>,
19854    ) {
19855        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19856
19857        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19858            self.start_git_blame(true, window, cx);
19859        }
19860
19861        cx.notify();
19862    }
19863
19864    pub fn toggle_git_blame_inline(
19865        &mut self,
19866        _: &ToggleGitBlameInline,
19867        window: &mut Window,
19868        cx: &mut Context<Self>,
19869    ) {
19870        self.toggle_git_blame_inline_internal(true, window, cx);
19871        cx.notify();
19872    }
19873
19874    pub fn open_git_blame_commit(
19875        &mut self,
19876        _: &OpenGitBlameCommit,
19877        window: &mut Window,
19878        cx: &mut Context<Self>,
19879    ) {
19880        self.open_git_blame_commit_internal(window, cx);
19881    }
19882
19883    fn open_git_blame_commit_internal(
19884        &mut self,
19885        window: &mut Window,
19886        cx: &mut Context<Self>,
19887    ) -> Option<()> {
19888        let blame = self.blame.as_ref()?;
19889        let snapshot = self.snapshot(window, cx);
19890        let cursor = self
19891            .selections
19892            .newest::<Point>(&snapshot.display_snapshot)
19893            .head();
19894        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19895        let (_, blame_entry) = blame
19896            .update(cx, |blame, cx| {
19897                blame
19898                    .blame_for_rows(
19899                        &[RowInfo {
19900                            buffer_id: Some(buffer.remote_id()),
19901                            buffer_row: Some(point.row),
19902                            ..Default::default()
19903                        }],
19904                        cx,
19905                    )
19906                    .next()
19907            })
19908            .flatten()?;
19909        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19910        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19911        let workspace = self.workspace()?.downgrade();
19912        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19913        None
19914    }
19915
19916    pub fn git_blame_inline_enabled(&self) -> bool {
19917        self.git_blame_inline_enabled
19918    }
19919
19920    pub fn toggle_selection_menu(
19921        &mut self,
19922        _: &ToggleSelectionMenu,
19923        _: &mut Window,
19924        cx: &mut Context<Self>,
19925    ) {
19926        self.show_selection_menu = self
19927            .show_selection_menu
19928            .map(|show_selections_menu| !show_selections_menu)
19929            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19930
19931        cx.notify();
19932    }
19933
19934    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19935        self.show_selection_menu
19936            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19937    }
19938
19939    fn start_git_blame(
19940        &mut self,
19941        user_triggered: bool,
19942        window: &mut Window,
19943        cx: &mut Context<Self>,
19944    ) {
19945        if let Some(project) = self.project() {
19946            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19947                && buffer.read(cx).file().is_none()
19948            {
19949                return;
19950            }
19951
19952            let focused = self.focus_handle(cx).contains_focused(window, cx);
19953
19954            let project = project.clone();
19955            let blame = cx
19956                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19957            self.blame_subscription =
19958                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19959            self.blame = Some(blame);
19960        }
19961    }
19962
19963    fn toggle_git_blame_inline_internal(
19964        &mut self,
19965        user_triggered: bool,
19966        window: &mut Window,
19967        cx: &mut Context<Self>,
19968    ) {
19969        if self.git_blame_inline_enabled {
19970            self.git_blame_inline_enabled = false;
19971            self.show_git_blame_inline = false;
19972            self.show_git_blame_inline_delay_task.take();
19973        } else {
19974            self.git_blame_inline_enabled = true;
19975            self.start_git_blame_inline(user_triggered, window, cx);
19976        }
19977
19978        cx.notify();
19979    }
19980
19981    fn start_git_blame_inline(
19982        &mut self,
19983        user_triggered: bool,
19984        window: &mut Window,
19985        cx: &mut Context<Self>,
19986    ) {
19987        self.start_git_blame(user_triggered, window, cx);
19988
19989        if ProjectSettings::get_global(cx)
19990            .git
19991            .inline_blame_delay()
19992            .is_some()
19993        {
19994            self.start_inline_blame_timer(window, cx);
19995        } else {
19996            self.show_git_blame_inline = true
19997        }
19998    }
19999
20000    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20001        self.blame.as_ref()
20002    }
20003
20004    pub fn show_git_blame_gutter(&self) -> bool {
20005        self.show_git_blame_gutter
20006    }
20007
20008    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20009        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20010    }
20011
20012    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20013        self.show_git_blame_inline
20014            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20015            && !self.newest_selection_head_on_empty_line(cx)
20016            && self.has_blame_entries(cx)
20017    }
20018
20019    fn has_blame_entries(&self, cx: &App) -> bool {
20020        self.blame()
20021            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20022    }
20023
20024    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20025        let cursor_anchor = self.selections.newest_anchor().head();
20026
20027        let snapshot = self.buffer.read(cx).snapshot(cx);
20028        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20029
20030        snapshot.line_len(buffer_row) == 0
20031    }
20032
20033    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20034        let buffer_and_selection = maybe!({
20035            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20036            let selection_range = selection.range();
20037
20038            let multi_buffer = self.buffer().read(cx);
20039            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20040            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20041
20042            let (buffer, range, _) = if selection.reversed {
20043                buffer_ranges.first()
20044            } else {
20045                buffer_ranges.last()
20046            }?;
20047
20048            let selection = text::ToPoint::to_point(&range.start, buffer).row
20049                ..text::ToPoint::to_point(&range.end, buffer).row;
20050            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20051        });
20052
20053        let Some((buffer, selection)) = buffer_and_selection else {
20054            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20055        };
20056
20057        let Some(project) = self.project() else {
20058            return Task::ready(Err(anyhow!("editor does not have project")));
20059        };
20060
20061        project.update(cx, |project, cx| {
20062            project.get_permalink_to_line(&buffer, selection, cx)
20063        })
20064    }
20065
20066    pub fn copy_permalink_to_line(
20067        &mut self,
20068        _: &CopyPermalinkToLine,
20069        window: &mut Window,
20070        cx: &mut Context<Self>,
20071    ) {
20072        let permalink_task = self.get_permalink_to_line(cx);
20073        let workspace = self.workspace();
20074
20075        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20076            Ok(permalink) => {
20077                cx.update(|_, cx| {
20078                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20079                })
20080                .ok();
20081            }
20082            Err(err) => {
20083                let message = format!("Failed to copy permalink: {err}");
20084
20085                anyhow::Result::<()>::Err(err).log_err();
20086
20087                if let Some(workspace) = workspace {
20088                    workspace
20089                        .update_in(cx, |workspace, _, cx| {
20090                            struct CopyPermalinkToLine;
20091
20092                            workspace.show_toast(
20093                                Toast::new(
20094                                    NotificationId::unique::<CopyPermalinkToLine>(),
20095                                    message,
20096                                ),
20097                                cx,
20098                            )
20099                        })
20100                        .ok();
20101                }
20102            }
20103        })
20104        .detach();
20105    }
20106
20107    pub fn copy_file_location(
20108        &mut self,
20109        _: &CopyFileLocation,
20110        _: &mut Window,
20111        cx: &mut Context<Self>,
20112    ) {
20113        let selection = self
20114            .selections
20115            .newest::<Point>(&self.display_snapshot(cx))
20116            .start
20117            .row
20118            + 1;
20119        if let Some(file) = self.target_file(cx) {
20120            let path = file.path().display(file.path_style(cx));
20121            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20122        }
20123    }
20124
20125    pub fn open_permalink_to_line(
20126        &mut self,
20127        _: &OpenPermalinkToLine,
20128        window: &mut Window,
20129        cx: &mut Context<Self>,
20130    ) {
20131        let permalink_task = self.get_permalink_to_line(cx);
20132        let workspace = self.workspace();
20133
20134        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20135            Ok(permalink) => {
20136                cx.update(|_, cx| {
20137                    cx.open_url(permalink.as_ref());
20138                })
20139                .ok();
20140            }
20141            Err(err) => {
20142                let message = format!("Failed to open permalink: {err}");
20143
20144                anyhow::Result::<()>::Err(err).log_err();
20145
20146                if let Some(workspace) = workspace {
20147                    workspace
20148                        .update(cx, |workspace, cx| {
20149                            struct OpenPermalinkToLine;
20150
20151                            workspace.show_toast(
20152                                Toast::new(
20153                                    NotificationId::unique::<OpenPermalinkToLine>(),
20154                                    message,
20155                                ),
20156                                cx,
20157                            )
20158                        })
20159                        .ok();
20160                }
20161            }
20162        })
20163        .detach();
20164    }
20165
20166    pub fn insert_uuid_v4(
20167        &mut self,
20168        _: &InsertUuidV4,
20169        window: &mut Window,
20170        cx: &mut Context<Self>,
20171    ) {
20172        self.insert_uuid(UuidVersion::V4, window, cx);
20173    }
20174
20175    pub fn insert_uuid_v7(
20176        &mut self,
20177        _: &InsertUuidV7,
20178        window: &mut Window,
20179        cx: &mut Context<Self>,
20180    ) {
20181        self.insert_uuid(UuidVersion::V7, window, cx);
20182    }
20183
20184    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20185        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20186        self.transact(window, cx, |this, window, cx| {
20187            let edits = this
20188                .selections
20189                .all::<Point>(&this.display_snapshot(cx))
20190                .into_iter()
20191                .map(|selection| {
20192                    let uuid = match version {
20193                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20194                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20195                    };
20196
20197                    (selection.range(), uuid.to_string())
20198                });
20199            this.edit(edits, cx);
20200            this.refresh_edit_prediction(true, false, window, cx);
20201        });
20202    }
20203
20204    pub fn open_selections_in_multibuffer(
20205        &mut self,
20206        _: &OpenSelectionsInMultibuffer,
20207        window: &mut Window,
20208        cx: &mut Context<Self>,
20209    ) {
20210        let multibuffer = self.buffer.read(cx);
20211
20212        let Some(buffer) = multibuffer.as_singleton() else {
20213            return;
20214        };
20215
20216        let Some(workspace) = self.workspace() else {
20217            return;
20218        };
20219
20220        let title = multibuffer.title(cx).to_string();
20221
20222        let locations = self
20223            .selections
20224            .all_anchors(cx)
20225            .iter()
20226            .map(|selection| {
20227                (
20228                    buffer.clone(),
20229                    (selection.start.text_anchor..selection.end.text_anchor)
20230                        .to_point(buffer.read(cx)),
20231                )
20232            })
20233            .into_group_map();
20234
20235        cx.spawn_in(window, async move |_, cx| {
20236            workspace.update_in(cx, |workspace, window, cx| {
20237                Self::open_locations_in_multibuffer(
20238                    workspace,
20239                    locations,
20240                    format!("Selections for '{title}'"),
20241                    false,
20242                    MultibufferSelectionMode::All,
20243                    window,
20244                    cx,
20245                );
20246            })
20247        })
20248        .detach();
20249    }
20250
20251    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20252    /// last highlight added will be used.
20253    ///
20254    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20255    pub fn highlight_rows<T: 'static>(
20256        &mut self,
20257        range: Range<Anchor>,
20258        color: Hsla,
20259        options: RowHighlightOptions,
20260        cx: &mut Context<Self>,
20261    ) {
20262        let snapshot = self.buffer().read(cx).snapshot(cx);
20263        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20264        let ix = row_highlights.binary_search_by(|highlight| {
20265            Ordering::Equal
20266                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20267                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20268        });
20269
20270        if let Err(mut ix) = ix {
20271            let index = post_inc(&mut self.highlight_order);
20272
20273            // If this range intersects with the preceding highlight, then merge it with
20274            // the preceding highlight. Otherwise insert a new highlight.
20275            let mut merged = false;
20276            if ix > 0 {
20277                let prev_highlight = &mut row_highlights[ix - 1];
20278                if prev_highlight
20279                    .range
20280                    .end
20281                    .cmp(&range.start, &snapshot)
20282                    .is_ge()
20283                {
20284                    ix -= 1;
20285                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20286                        prev_highlight.range.end = range.end;
20287                    }
20288                    merged = true;
20289                    prev_highlight.index = index;
20290                    prev_highlight.color = color;
20291                    prev_highlight.options = options;
20292                }
20293            }
20294
20295            if !merged {
20296                row_highlights.insert(
20297                    ix,
20298                    RowHighlight {
20299                        range,
20300                        index,
20301                        color,
20302                        options,
20303                        type_id: TypeId::of::<T>(),
20304                    },
20305                );
20306            }
20307
20308            // If any of the following highlights intersect with this one, merge them.
20309            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20310                let highlight = &row_highlights[ix];
20311                if next_highlight
20312                    .range
20313                    .start
20314                    .cmp(&highlight.range.end, &snapshot)
20315                    .is_le()
20316                {
20317                    if next_highlight
20318                        .range
20319                        .end
20320                        .cmp(&highlight.range.end, &snapshot)
20321                        .is_gt()
20322                    {
20323                        row_highlights[ix].range.end = next_highlight.range.end;
20324                    }
20325                    row_highlights.remove(ix + 1);
20326                } else {
20327                    break;
20328                }
20329            }
20330        }
20331    }
20332
20333    /// Remove any highlighted row ranges of the given type that intersect the
20334    /// given ranges.
20335    pub fn remove_highlighted_rows<T: 'static>(
20336        &mut self,
20337        ranges_to_remove: Vec<Range<Anchor>>,
20338        cx: &mut Context<Self>,
20339    ) {
20340        let snapshot = self.buffer().read(cx).snapshot(cx);
20341        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20342        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20343        row_highlights.retain(|highlight| {
20344            while let Some(range_to_remove) = ranges_to_remove.peek() {
20345                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20346                    Ordering::Less | Ordering::Equal => {
20347                        ranges_to_remove.next();
20348                    }
20349                    Ordering::Greater => {
20350                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20351                            Ordering::Less | Ordering::Equal => {
20352                                return false;
20353                            }
20354                            Ordering::Greater => break,
20355                        }
20356                    }
20357                }
20358            }
20359
20360            true
20361        })
20362    }
20363
20364    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20365    pub fn clear_row_highlights<T: 'static>(&mut self) {
20366        self.highlighted_rows.remove(&TypeId::of::<T>());
20367    }
20368
20369    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20370    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20371        self.highlighted_rows
20372            .get(&TypeId::of::<T>())
20373            .map_or(&[] as &[_], |vec| vec.as_slice())
20374            .iter()
20375            .map(|highlight| (highlight.range.clone(), highlight.color))
20376    }
20377
20378    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20379    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20380    /// Allows to ignore certain kinds of highlights.
20381    pub fn highlighted_display_rows(
20382        &self,
20383        window: &mut Window,
20384        cx: &mut App,
20385    ) -> BTreeMap<DisplayRow, LineHighlight> {
20386        let snapshot = self.snapshot(window, cx);
20387        let mut used_highlight_orders = HashMap::default();
20388        self.highlighted_rows
20389            .iter()
20390            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20391            .fold(
20392                BTreeMap::<DisplayRow, LineHighlight>::new(),
20393                |mut unique_rows, highlight| {
20394                    let start = highlight.range.start.to_display_point(&snapshot);
20395                    let end = highlight.range.end.to_display_point(&snapshot);
20396                    let start_row = start.row().0;
20397                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20398                        && end.column() == 0
20399                    {
20400                        end.row().0.saturating_sub(1)
20401                    } else {
20402                        end.row().0
20403                    };
20404                    for row in start_row..=end_row {
20405                        let used_index =
20406                            used_highlight_orders.entry(row).or_insert(highlight.index);
20407                        if highlight.index >= *used_index {
20408                            *used_index = highlight.index;
20409                            unique_rows.insert(
20410                                DisplayRow(row),
20411                                LineHighlight {
20412                                    include_gutter: highlight.options.include_gutter,
20413                                    border: None,
20414                                    background: highlight.color.into(),
20415                                    type_id: Some(highlight.type_id),
20416                                },
20417                            );
20418                        }
20419                    }
20420                    unique_rows
20421                },
20422            )
20423    }
20424
20425    pub fn highlighted_display_row_for_autoscroll(
20426        &self,
20427        snapshot: &DisplaySnapshot,
20428    ) -> Option<DisplayRow> {
20429        self.highlighted_rows
20430            .values()
20431            .flat_map(|highlighted_rows| highlighted_rows.iter())
20432            .filter_map(|highlight| {
20433                if highlight.options.autoscroll {
20434                    Some(highlight.range.start.to_display_point(snapshot).row())
20435                } else {
20436                    None
20437                }
20438            })
20439            .min()
20440    }
20441
20442    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20443        self.highlight_background::<SearchWithinRange>(
20444            ranges,
20445            |colors| colors.colors().editor_document_highlight_read_background,
20446            cx,
20447        )
20448    }
20449
20450    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20451        self.breadcrumb_header = Some(new_header);
20452    }
20453
20454    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20455        self.clear_background_highlights::<SearchWithinRange>(cx);
20456    }
20457
20458    pub fn highlight_background<T: 'static>(
20459        &mut self,
20460        ranges: &[Range<Anchor>],
20461        color_fetcher: fn(&Theme) -> Hsla,
20462        cx: &mut Context<Self>,
20463    ) {
20464        self.background_highlights.insert(
20465            HighlightKey::Type(TypeId::of::<T>()),
20466            (color_fetcher, Arc::from(ranges)),
20467        );
20468        self.scrollbar_marker_state.dirty = true;
20469        cx.notify();
20470    }
20471
20472    pub fn highlight_background_key<T: 'static>(
20473        &mut self,
20474        key: usize,
20475        ranges: &[Range<Anchor>],
20476        color_fetcher: fn(&Theme) -> Hsla,
20477        cx: &mut Context<Self>,
20478    ) {
20479        self.background_highlights.insert(
20480            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20481            (color_fetcher, Arc::from(ranges)),
20482        );
20483        self.scrollbar_marker_state.dirty = true;
20484        cx.notify();
20485    }
20486
20487    pub fn clear_background_highlights<T: 'static>(
20488        &mut self,
20489        cx: &mut Context<Self>,
20490    ) -> Option<BackgroundHighlight> {
20491        let text_highlights = self
20492            .background_highlights
20493            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20494        if !text_highlights.1.is_empty() {
20495            self.scrollbar_marker_state.dirty = true;
20496            cx.notify();
20497        }
20498        Some(text_highlights)
20499    }
20500
20501    pub fn highlight_gutter<T: 'static>(
20502        &mut self,
20503        ranges: impl Into<Vec<Range<Anchor>>>,
20504        color_fetcher: fn(&App) -> Hsla,
20505        cx: &mut Context<Self>,
20506    ) {
20507        self.gutter_highlights
20508            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20509        cx.notify();
20510    }
20511
20512    pub fn clear_gutter_highlights<T: 'static>(
20513        &mut self,
20514        cx: &mut Context<Self>,
20515    ) -> Option<GutterHighlight> {
20516        cx.notify();
20517        self.gutter_highlights.remove(&TypeId::of::<T>())
20518    }
20519
20520    pub fn insert_gutter_highlight<T: 'static>(
20521        &mut self,
20522        range: Range<Anchor>,
20523        color_fetcher: fn(&App) -> Hsla,
20524        cx: &mut Context<Self>,
20525    ) {
20526        let snapshot = self.buffer().read(cx).snapshot(cx);
20527        let mut highlights = self
20528            .gutter_highlights
20529            .remove(&TypeId::of::<T>())
20530            .map(|(_, highlights)| highlights)
20531            .unwrap_or_default();
20532        let ix = highlights.binary_search_by(|highlight| {
20533            Ordering::Equal
20534                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20535                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20536        });
20537        if let Err(ix) = ix {
20538            highlights.insert(ix, range);
20539        }
20540        self.gutter_highlights
20541            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20542    }
20543
20544    pub fn remove_gutter_highlights<T: 'static>(
20545        &mut self,
20546        ranges_to_remove: Vec<Range<Anchor>>,
20547        cx: &mut Context<Self>,
20548    ) {
20549        let snapshot = self.buffer().read(cx).snapshot(cx);
20550        let Some((color_fetcher, mut gutter_highlights)) =
20551            self.gutter_highlights.remove(&TypeId::of::<T>())
20552        else {
20553            return;
20554        };
20555        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20556        gutter_highlights.retain(|highlight| {
20557            while let Some(range_to_remove) = ranges_to_remove.peek() {
20558                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20559                    Ordering::Less | Ordering::Equal => {
20560                        ranges_to_remove.next();
20561                    }
20562                    Ordering::Greater => {
20563                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20564                            Ordering::Less | Ordering::Equal => {
20565                                return false;
20566                            }
20567                            Ordering::Greater => break,
20568                        }
20569                    }
20570                }
20571            }
20572
20573            true
20574        });
20575        self.gutter_highlights
20576            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20577    }
20578
20579    #[cfg(feature = "test-support")]
20580    pub fn all_text_highlights(
20581        &self,
20582        window: &mut Window,
20583        cx: &mut Context<Self>,
20584    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20585        let snapshot = self.snapshot(window, cx);
20586        self.display_map.update(cx, |display_map, _| {
20587            display_map
20588                .all_text_highlights()
20589                .map(|highlight| {
20590                    let (style, ranges) = highlight.as_ref();
20591                    (
20592                        *style,
20593                        ranges
20594                            .iter()
20595                            .map(|range| range.clone().to_display_points(&snapshot))
20596                            .collect(),
20597                    )
20598                })
20599                .collect()
20600        })
20601    }
20602
20603    #[cfg(feature = "test-support")]
20604    pub fn all_text_background_highlights(
20605        &self,
20606        window: &mut Window,
20607        cx: &mut Context<Self>,
20608    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20609        let snapshot = self.snapshot(window, cx);
20610        let buffer = &snapshot.buffer_snapshot();
20611        let start = buffer.anchor_before(0);
20612        let end = buffer.anchor_after(buffer.len());
20613        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20614    }
20615
20616    #[cfg(any(test, feature = "test-support"))]
20617    pub fn sorted_background_highlights_in_range(
20618        &self,
20619        search_range: Range<Anchor>,
20620        display_snapshot: &DisplaySnapshot,
20621        theme: &Theme,
20622    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20623        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20624        res.sort_by(|a, b| {
20625            a.0.start
20626                .cmp(&b.0.start)
20627                .then_with(|| a.0.end.cmp(&b.0.end))
20628                .then_with(|| a.1.cmp(&b.1))
20629        });
20630        res
20631    }
20632
20633    #[cfg(feature = "test-support")]
20634    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20635        let snapshot = self.buffer().read(cx).snapshot(cx);
20636
20637        let highlights = self
20638            .background_highlights
20639            .get(&HighlightKey::Type(TypeId::of::<
20640                items::BufferSearchHighlights,
20641            >()));
20642
20643        if let Some((_color, ranges)) = highlights {
20644            ranges
20645                .iter()
20646                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20647                .collect_vec()
20648        } else {
20649            vec![]
20650        }
20651    }
20652
20653    fn document_highlights_for_position<'a>(
20654        &'a self,
20655        position: Anchor,
20656        buffer: &'a MultiBufferSnapshot,
20657    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20658        let read_highlights = self
20659            .background_highlights
20660            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20661            .map(|h| &h.1);
20662        let write_highlights = self
20663            .background_highlights
20664            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20665            .map(|h| &h.1);
20666        let left_position = position.bias_left(buffer);
20667        let right_position = position.bias_right(buffer);
20668        read_highlights
20669            .into_iter()
20670            .chain(write_highlights)
20671            .flat_map(move |ranges| {
20672                let start_ix = match ranges.binary_search_by(|probe| {
20673                    let cmp = probe.end.cmp(&left_position, buffer);
20674                    if cmp.is_ge() {
20675                        Ordering::Greater
20676                    } else {
20677                        Ordering::Less
20678                    }
20679                }) {
20680                    Ok(i) | Err(i) => i,
20681                };
20682
20683                ranges[start_ix..]
20684                    .iter()
20685                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20686            })
20687    }
20688
20689    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20690        self.background_highlights
20691            .get(&HighlightKey::Type(TypeId::of::<T>()))
20692            .is_some_and(|(_, highlights)| !highlights.is_empty())
20693    }
20694
20695    /// Returns all background highlights for a given range.
20696    ///
20697    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20698    pub fn background_highlights_in_range(
20699        &self,
20700        search_range: Range<Anchor>,
20701        display_snapshot: &DisplaySnapshot,
20702        theme: &Theme,
20703    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20704        let mut results = Vec::new();
20705        for (color_fetcher, ranges) in self.background_highlights.values() {
20706            let color = color_fetcher(theme);
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    pub fn gutter_highlights_in_range(
20737        &self,
20738        search_range: Range<Anchor>,
20739        display_snapshot: &DisplaySnapshot,
20740        cx: &App,
20741    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20742        let mut results = Vec::new();
20743        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20744            let color = color_fetcher(cx);
20745            let start_ix = match ranges.binary_search_by(|probe| {
20746                let cmp = probe
20747                    .end
20748                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20749                if cmp.is_gt() {
20750                    Ordering::Greater
20751                } else {
20752                    Ordering::Less
20753                }
20754            }) {
20755                Ok(i) | Err(i) => i,
20756            };
20757            for range in &ranges[start_ix..] {
20758                if range
20759                    .start
20760                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20761                    .is_ge()
20762                {
20763                    break;
20764                }
20765
20766                let start = range.start.to_display_point(display_snapshot);
20767                let end = range.end.to_display_point(display_snapshot);
20768                results.push((start..end, color))
20769            }
20770        }
20771        results
20772    }
20773
20774    /// Get the text ranges corresponding to the redaction query
20775    pub fn redacted_ranges(
20776        &self,
20777        search_range: Range<Anchor>,
20778        display_snapshot: &DisplaySnapshot,
20779        cx: &App,
20780    ) -> Vec<Range<DisplayPoint>> {
20781        display_snapshot
20782            .buffer_snapshot()
20783            .redacted_ranges(search_range, |file| {
20784                if let Some(file) = file {
20785                    file.is_private()
20786                        && EditorSettings::get(
20787                            Some(SettingsLocation {
20788                                worktree_id: file.worktree_id(cx),
20789                                path: file.path().as_ref(),
20790                            }),
20791                            cx,
20792                        )
20793                        .redact_private_values
20794                } else {
20795                    false
20796                }
20797            })
20798            .map(|range| {
20799                range.start.to_display_point(display_snapshot)
20800                    ..range.end.to_display_point(display_snapshot)
20801            })
20802            .collect()
20803    }
20804
20805    pub fn highlight_text_key<T: 'static>(
20806        &mut self,
20807        key: usize,
20808        ranges: Vec<Range<Anchor>>,
20809        style: HighlightStyle,
20810        cx: &mut Context<Self>,
20811    ) {
20812        self.display_map.update(cx, |map, _| {
20813            map.highlight_text(
20814                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20815                ranges,
20816                style,
20817            );
20818        });
20819        cx.notify();
20820    }
20821
20822    pub fn highlight_text<T: 'static>(
20823        &mut self,
20824        ranges: Vec<Range<Anchor>>,
20825        style: HighlightStyle,
20826        cx: &mut Context<Self>,
20827    ) {
20828        self.display_map.update(cx, |map, _| {
20829            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20830        });
20831        cx.notify();
20832    }
20833
20834    pub fn text_highlights<'a, T: 'static>(
20835        &'a self,
20836        cx: &'a App,
20837    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20838        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20839    }
20840
20841    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20842        let cleared = self
20843            .display_map
20844            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20845        if cleared {
20846            cx.notify();
20847        }
20848    }
20849
20850    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20851        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20852            && self.focus_handle.is_focused(window)
20853    }
20854
20855    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20856        self.show_cursor_when_unfocused = is_enabled;
20857        cx.notify();
20858    }
20859
20860    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20861        cx.notify();
20862    }
20863
20864    fn on_debug_session_event(
20865        &mut self,
20866        _session: Entity<Session>,
20867        event: &SessionEvent,
20868        cx: &mut Context<Self>,
20869    ) {
20870        if let SessionEvent::InvalidateInlineValue = event {
20871            self.refresh_inline_values(cx);
20872        }
20873    }
20874
20875    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20876        let Some(project) = self.project.clone() else {
20877            return;
20878        };
20879
20880        if !self.inline_value_cache.enabled {
20881            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20882            self.splice_inlays(&inlays, Vec::new(), cx);
20883            return;
20884        }
20885
20886        let current_execution_position = self
20887            .highlighted_rows
20888            .get(&TypeId::of::<ActiveDebugLine>())
20889            .and_then(|lines| lines.last().map(|line| line.range.end));
20890
20891        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20892            let inline_values = editor
20893                .update(cx, |editor, cx| {
20894                    let Some(current_execution_position) = current_execution_position else {
20895                        return Some(Task::ready(Ok(Vec::new())));
20896                    };
20897
20898                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20899                        let snapshot = buffer.snapshot(cx);
20900
20901                        let excerpt = snapshot.excerpt_containing(
20902                            current_execution_position..current_execution_position,
20903                        )?;
20904
20905                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20906                    })?;
20907
20908                    let range =
20909                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20910
20911                    project.inline_values(buffer, range, cx)
20912                })
20913                .ok()
20914                .flatten()?
20915                .await
20916                .context("refreshing debugger inlays")
20917                .log_err()?;
20918
20919            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20920
20921            for (buffer_id, inline_value) in inline_values
20922                .into_iter()
20923                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20924            {
20925                buffer_inline_values
20926                    .entry(buffer_id)
20927                    .or_default()
20928                    .push(inline_value);
20929            }
20930
20931            editor
20932                .update(cx, |editor, cx| {
20933                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20934                    let mut new_inlays = Vec::default();
20935
20936                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20937                        let buffer_id = buffer_snapshot.remote_id();
20938                        buffer_inline_values
20939                            .get(&buffer_id)
20940                            .into_iter()
20941                            .flatten()
20942                            .for_each(|hint| {
20943                                let inlay = Inlay::debugger(
20944                                    post_inc(&mut editor.next_inlay_id),
20945                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20946                                    hint.text(),
20947                                );
20948                                if !inlay.text().chars().contains(&'\n') {
20949                                    new_inlays.push(inlay);
20950                                }
20951                            });
20952                    }
20953
20954                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20955                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20956
20957                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20958                })
20959                .ok()?;
20960            Some(())
20961        });
20962    }
20963
20964    fn on_buffer_event(
20965        &mut self,
20966        multibuffer: &Entity<MultiBuffer>,
20967        event: &multi_buffer::Event,
20968        window: &mut Window,
20969        cx: &mut Context<Self>,
20970    ) {
20971        match event {
20972            multi_buffer::Event::Edited { edited_buffer } => {
20973                self.scrollbar_marker_state.dirty = true;
20974                self.active_indent_guides_state.dirty = true;
20975                self.refresh_active_diagnostics(cx);
20976                self.refresh_code_actions(window, cx);
20977                self.refresh_selected_text_highlights(true, window, cx);
20978                self.refresh_single_line_folds(window, cx);
20979                self.refresh_matching_bracket_highlights(window, cx);
20980                if self.has_active_edit_prediction() {
20981                    self.update_visible_edit_prediction(window, cx);
20982                }
20983
20984                if let Some(buffer) = edited_buffer {
20985                    if buffer.read(cx).file().is_none() {
20986                        cx.emit(EditorEvent::TitleChanged);
20987                    }
20988
20989                    if self.project.is_some() {
20990                        let buffer_id = buffer.read(cx).remote_id();
20991                        self.register_buffer(buffer_id, cx);
20992                        self.update_lsp_data(Some(buffer_id), window, cx);
20993                        self.refresh_inlay_hints(
20994                            InlayHintRefreshReason::BufferEdited(buffer_id),
20995                            cx,
20996                        );
20997                    }
20998                }
20999
21000                cx.emit(EditorEvent::BufferEdited);
21001                cx.emit(SearchEvent::MatchesInvalidated);
21002
21003                let Some(project) = &self.project else { return };
21004                let (telemetry, is_via_ssh) = {
21005                    let project = project.read(cx);
21006                    let telemetry = project.client().telemetry().clone();
21007                    let is_via_ssh = project.is_via_remote_server();
21008                    (telemetry, is_via_ssh)
21009                };
21010                telemetry.log_edit_event("editor", is_via_ssh);
21011            }
21012            multi_buffer::Event::ExcerptsAdded {
21013                buffer,
21014                predecessor,
21015                excerpts,
21016            } => {
21017                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21018                let buffer_id = buffer.read(cx).remote_id();
21019                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21020                    && let Some(project) = &self.project
21021                {
21022                    update_uncommitted_diff_for_buffer(
21023                        cx.entity(),
21024                        project,
21025                        [buffer.clone()],
21026                        self.buffer.clone(),
21027                        cx,
21028                    )
21029                    .detach();
21030                }
21031                self.update_lsp_data(Some(buffer_id), window, cx);
21032                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21033                cx.emit(EditorEvent::ExcerptsAdded {
21034                    buffer: buffer.clone(),
21035                    predecessor: *predecessor,
21036                    excerpts: excerpts.clone(),
21037                });
21038            }
21039            multi_buffer::Event::ExcerptsRemoved {
21040                ids,
21041                removed_buffer_ids,
21042            } => {
21043                if let Some(inlay_hints) = &mut self.inlay_hints {
21044                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21045                }
21046                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21047                for buffer_id in removed_buffer_ids {
21048                    self.registered_buffers.remove(buffer_id);
21049                }
21050                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21051                cx.emit(EditorEvent::ExcerptsRemoved {
21052                    ids: ids.clone(),
21053                    removed_buffer_ids: removed_buffer_ids.clone(),
21054                });
21055            }
21056            multi_buffer::Event::ExcerptsEdited {
21057                excerpt_ids,
21058                buffer_ids,
21059            } => {
21060                self.display_map.update(cx, |map, cx| {
21061                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21062                });
21063                cx.emit(EditorEvent::ExcerptsEdited {
21064                    ids: excerpt_ids.clone(),
21065                });
21066            }
21067            multi_buffer::Event::ExcerptsExpanded { ids } => {
21068                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21069                self.refresh_document_highlights(cx);
21070                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21071            }
21072            multi_buffer::Event::Reparsed(buffer_id) => {
21073                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21074                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21075
21076                cx.emit(EditorEvent::Reparsed(*buffer_id));
21077            }
21078            multi_buffer::Event::DiffHunksToggled => {
21079                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21080            }
21081            multi_buffer::Event::LanguageChanged(buffer_id) => {
21082                self.registered_buffers.remove(&buffer_id);
21083                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21084                cx.emit(EditorEvent::Reparsed(*buffer_id));
21085                cx.notify();
21086            }
21087            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21088            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21089            multi_buffer::Event::FileHandleChanged
21090            | multi_buffer::Event::Reloaded
21091            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21092            multi_buffer::Event::DiagnosticsUpdated => {
21093                self.update_diagnostics_state(window, cx);
21094            }
21095            _ => {}
21096        };
21097    }
21098
21099    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21100        if !self.diagnostics_enabled() {
21101            return;
21102        }
21103        self.refresh_active_diagnostics(cx);
21104        self.refresh_inline_diagnostics(true, window, cx);
21105        self.scrollbar_marker_state.dirty = true;
21106        cx.notify();
21107    }
21108
21109    pub fn start_temporary_diff_override(&mut self) {
21110        self.load_diff_task.take();
21111        self.temporary_diff_override = true;
21112    }
21113
21114    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21115        self.temporary_diff_override = false;
21116        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21117        self.buffer.update(cx, |buffer, cx| {
21118            buffer.set_all_diff_hunks_collapsed(cx);
21119        });
21120
21121        if let Some(project) = self.project.clone() {
21122            self.load_diff_task = Some(
21123                update_uncommitted_diff_for_buffer(
21124                    cx.entity(),
21125                    &project,
21126                    self.buffer.read(cx).all_buffers(),
21127                    self.buffer.clone(),
21128                    cx,
21129                )
21130                .shared(),
21131            );
21132        }
21133    }
21134
21135    fn on_display_map_changed(
21136        &mut self,
21137        _: Entity<DisplayMap>,
21138        _: &mut Window,
21139        cx: &mut Context<Self>,
21140    ) {
21141        cx.notify();
21142    }
21143
21144    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21145        if self.diagnostics_enabled() {
21146            let new_severity = EditorSettings::get_global(cx)
21147                .diagnostics_max_severity
21148                .unwrap_or(DiagnosticSeverity::Hint);
21149            self.set_max_diagnostics_severity(new_severity, cx);
21150        }
21151        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21152        self.update_edit_prediction_settings(cx);
21153        self.refresh_edit_prediction(true, false, window, cx);
21154        self.refresh_inline_values(cx);
21155        self.refresh_inlay_hints(
21156            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21157                self.selections.newest_anchor().head(),
21158                &self.buffer.read(cx).snapshot(cx),
21159                cx,
21160            )),
21161            cx,
21162        );
21163
21164        let old_cursor_shape = self.cursor_shape;
21165        let old_show_breadcrumbs = self.show_breadcrumbs;
21166
21167        {
21168            let editor_settings = EditorSettings::get_global(cx);
21169            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21170            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21171            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21172            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21173        }
21174
21175        if old_cursor_shape != self.cursor_shape {
21176            cx.emit(EditorEvent::CursorShapeChanged);
21177        }
21178
21179        if old_show_breadcrumbs != self.show_breadcrumbs {
21180            cx.emit(EditorEvent::BreadcrumbsChanged);
21181        }
21182
21183        let project_settings = ProjectSettings::get_global(cx);
21184        self.serialize_dirty_buffers =
21185            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21186
21187        if self.mode.is_full() {
21188            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21189            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21190            if self.show_inline_diagnostics != show_inline_diagnostics {
21191                self.show_inline_diagnostics = show_inline_diagnostics;
21192                self.refresh_inline_diagnostics(false, window, cx);
21193            }
21194
21195            if self.git_blame_inline_enabled != inline_blame_enabled {
21196                self.toggle_git_blame_inline_internal(false, window, cx);
21197            }
21198
21199            let minimap_settings = EditorSettings::get_global(cx).minimap;
21200            if self.minimap_visibility != MinimapVisibility::Disabled {
21201                if self.minimap_visibility.settings_visibility()
21202                    != minimap_settings.minimap_enabled()
21203                {
21204                    self.set_minimap_visibility(
21205                        MinimapVisibility::for_mode(self.mode(), cx),
21206                        window,
21207                        cx,
21208                    );
21209                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21210                    minimap_entity.update(cx, |minimap_editor, cx| {
21211                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21212                    })
21213                }
21214            }
21215        }
21216
21217        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21218            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21219        }) {
21220            if !inlay_splice.is_empty() {
21221                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21222            }
21223            self.refresh_colors_for_visible_range(None, window, cx);
21224        }
21225
21226        cx.notify();
21227    }
21228
21229    pub fn set_searchable(&mut self, searchable: bool) {
21230        self.searchable = searchable;
21231    }
21232
21233    pub fn searchable(&self) -> bool {
21234        self.searchable
21235    }
21236
21237    pub fn open_excerpts_in_split(
21238        &mut self,
21239        _: &OpenExcerptsSplit,
21240        window: &mut Window,
21241        cx: &mut Context<Self>,
21242    ) {
21243        self.open_excerpts_common(None, true, window, cx)
21244    }
21245
21246    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21247        self.open_excerpts_common(None, false, window, cx)
21248    }
21249
21250    fn open_excerpts_common(
21251        &mut self,
21252        jump_data: Option<JumpData>,
21253        split: bool,
21254        window: &mut Window,
21255        cx: &mut Context<Self>,
21256    ) {
21257        let Some(workspace) = self.workspace() else {
21258            cx.propagate();
21259            return;
21260        };
21261
21262        if self.buffer.read(cx).is_singleton() {
21263            cx.propagate();
21264            return;
21265        }
21266
21267        let mut new_selections_by_buffer = HashMap::default();
21268        match &jump_data {
21269            Some(JumpData::MultiBufferPoint {
21270                excerpt_id,
21271                position,
21272                anchor,
21273                line_offset_from_top,
21274            }) => {
21275                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21276                if let Some(buffer) = multi_buffer_snapshot
21277                    .buffer_id_for_excerpt(*excerpt_id)
21278                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21279                {
21280                    let buffer_snapshot = buffer.read(cx).snapshot();
21281                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21282                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21283                    } else {
21284                        buffer_snapshot.clip_point(*position, Bias::Left)
21285                    };
21286                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21287                    new_selections_by_buffer.insert(
21288                        buffer,
21289                        (
21290                            vec![jump_to_offset..jump_to_offset],
21291                            Some(*line_offset_from_top),
21292                        ),
21293                    );
21294                }
21295            }
21296            Some(JumpData::MultiBufferRow {
21297                row,
21298                line_offset_from_top,
21299            }) => {
21300                let point = MultiBufferPoint::new(row.0, 0);
21301                if let Some((buffer, buffer_point, _)) =
21302                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21303                {
21304                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21305                    new_selections_by_buffer
21306                        .entry(buffer)
21307                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21308                        .0
21309                        .push(buffer_offset..buffer_offset)
21310                }
21311            }
21312            None => {
21313                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21314                let multi_buffer = self.buffer.read(cx);
21315                for selection in selections {
21316                    for (snapshot, range, _, anchor) in multi_buffer
21317                        .snapshot(cx)
21318                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21319                    {
21320                        if let Some(anchor) = anchor {
21321                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21322                            else {
21323                                continue;
21324                            };
21325                            let offset = text::ToOffset::to_offset(
21326                                &anchor.text_anchor,
21327                                &buffer_handle.read(cx).snapshot(),
21328                            );
21329                            let range = offset..offset;
21330                            new_selections_by_buffer
21331                                .entry(buffer_handle)
21332                                .or_insert((Vec::new(), None))
21333                                .0
21334                                .push(range)
21335                        } else {
21336                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21337                            else {
21338                                continue;
21339                            };
21340                            new_selections_by_buffer
21341                                .entry(buffer_handle)
21342                                .or_insert((Vec::new(), None))
21343                                .0
21344                                .push(range)
21345                        }
21346                    }
21347                }
21348            }
21349        }
21350
21351        new_selections_by_buffer
21352            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21353
21354        if new_selections_by_buffer.is_empty() {
21355            return;
21356        }
21357
21358        // We defer the pane interaction because we ourselves are a workspace item
21359        // and activating a new item causes the pane to call a method on us reentrantly,
21360        // which panics if we're on the stack.
21361        window.defer(cx, move |window, cx| {
21362            workspace.update(cx, |workspace, cx| {
21363                let pane = if split {
21364                    workspace.adjacent_pane(window, cx)
21365                } else {
21366                    workspace.active_pane().clone()
21367                };
21368
21369                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21370                    let editor = buffer
21371                        .read(cx)
21372                        .file()
21373                        .is_none()
21374                        .then(|| {
21375                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21376                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21377                            // Instead, we try to activate the existing editor in the pane first.
21378                            let (editor, pane_item_index) =
21379                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21380                                    let editor = item.downcast::<Editor>()?;
21381                                    let singleton_buffer =
21382                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21383                                    if singleton_buffer == buffer {
21384                                        Some((editor, i))
21385                                    } else {
21386                                        None
21387                                    }
21388                                })?;
21389                            pane.update(cx, |pane, cx| {
21390                                pane.activate_item(pane_item_index, true, true, window, cx)
21391                            });
21392                            Some(editor)
21393                        })
21394                        .flatten()
21395                        .unwrap_or_else(|| {
21396                            workspace.open_project_item::<Self>(
21397                                pane.clone(),
21398                                buffer,
21399                                true,
21400                                true,
21401                                window,
21402                                cx,
21403                            )
21404                        });
21405
21406                    editor.update(cx, |editor, cx| {
21407                        let autoscroll = match scroll_offset {
21408                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21409                            None => Autoscroll::newest(),
21410                        };
21411                        let nav_history = editor.nav_history.take();
21412                        editor.change_selections(
21413                            SelectionEffects::scroll(autoscroll),
21414                            window,
21415                            cx,
21416                            |s| {
21417                                s.select_ranges(ranges);
21418                            },
21419                        );
21420                        editor.nav_history = nav_history;
21421                    });
21422                }
21423            })
21424        });
21425    }
21426
21427    // For now, don't allow opening excerpts in buffers that aren't backed by
21428    // regular project files.
21429    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21430        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21431    }
21432
21433    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21434        let snapshot = self.buffer.read(cx).read(cx);
21435        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21436        Some(
21437            ranges
21438                .iter()
21439                .map(move |range| {
21440                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21441                })
21442                .collect(),
21443        )
21444    }
21445
21446    fn selection_replacement_ranges(
21447        &self,
21448        range: Range<OffsetUtf16>,
21449        cx: &mut App,
21450    ) -> Vec<Range<OffsetUtf16>> {
21451        let selections = self
21452            .selections
21453            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21454        let newest_selection = selections
21455            .iter()
21456            .max_by_key(|selection| selection.id)
21457            .unwrap();
21458        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21459        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21460        let snapshot = self.buffer.read(cx).read(cx);
21461        selections
21462            .into_iter()
21463            .map(|mut selection| {
21464                selection.start.0 =
21465                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21466                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21467                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21468                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21469            })
21470            .collect()
21471    }
21472
21473    fn report_editor_event(
21474        &self,
21475        reported_event: ReportEditorEvent,
21476        file_extension: Option<String>,
21477        cx: &App,
21478    ) {
21479        if cfg!(any(test, feature = "test-support")) {
21480            return;
21481        }
21482
21483        let Some(project) = &self.project else { return };
21484
21485        // If None, we are in a file without an extension
21486        let file = self
21487            .buffer
21488            .read(cx)
21489            .as_singleton()
21490            .and_then(|b| b.read(cx).file());
21491        let file_extension = file_extension.or(file
21492            .as_ref()
21493            .and_then(|file| Path::new(file.file_name(cx)).extension())
21494            .and_then(|e| e.to_str())
21495            .map(|a| a.to_string()));
21496
21497        let vim_mode = vim_flavor(cx).is_some();
21498
21499        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21500        let copilot_enabled = edit_predictions_provider
21501            == language::language_settings::EditPredictionProvider::Copilot;
21502        let copilot_enabled_for_language = self
21503            .buffer
21504            .read(cx)
21505            .language_settings(cx)
21506            .show_edit_predictions;
21507
21508        let project = project.read(cx);
21509        let event_type = reported_event.event_type();
21510
21511        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21512            telemetry::event!(
21513                event_type,
21514                type = if auto_saved {"autosave"} else {"manual"},
21515                file_extension,
21516                vim_mode,
21517                copilot_enabled,
21518                copilot_enabled_for_language,
21519                edit_predictions_provider,
21520                is_via_ssh = project.is_via_remote_server(),
21521            );
21522        } else {
21523            telemetry::event!(
21524                event_type,
21525                file_extension,
21526                vim_mode,
21527                copilot_enabled,
21528                copilot_enabled_for_language,
21529                edit_predictions_provider,
21530                is_via_ssh = project.is_via_remote_server(),
21531            );
21532        };
21533    }
21534
21535    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21536    /// with each line being an array of {text, highlight} objects.
21537    fn copy_highlight_json(
21538        &mut self,
21539        _: &CopyHighlightJson,
21540        window: &mut Window,
21541        cx: &mut Context<Self>,
21542    ) {
21543        #[derive(Serialize)]
21544        struct Chunk<'a> {
21545            text: String,
21546            highlight: Option<&'a str>,
21547        }
21548
21549        let snapshot = self.buffer.read(cx).snapshot(cx);
21550        let range = self
21551            .selected_text_range(false, window, cx)
21552            .and_then(|selection| {
21553                if selection.range.is_empty() {
21554                    None
21555                } else {
21556                    Some(
21557                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21558                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21559                    )
21560                }
21561            })
21562            .unwrap_or_else(|| 0..snapshot.len());
21563
21564        let chunks = snapshot.chunks(range, true);
21565        let mut lines = Vec::new();
21566        let mut line: VecDeque<Chunk> = VecDeque::new();
21567
21568        let Some(style) = self.style.as_ref() else {
21569            return;
21570        };
21571
21572        for chunk in chunks {
21573            let highlight = chunk
21574                .syntax_highlight_id
21575                .and_then(|id| id.name(&style.syntax));
21576            let mut chunk_lines = chunk.text.split('\n').peekable();
21577            while let Some(text) = chunk_lines.next() {
21578                let mut merged_with_last_token = false;
21579                if let Some(last_token) = line.back_mut()
21580                    && last_token.highlight == highlight
21581                {
21582                    last_token.text.push_str(text);
21583                    merged_with_last_token = true;
21584                }
21585
21586                if !merged_with_last_token {
21587                    line.push_back(Chunk {
21588                        text: text.into(),
21589                        highlight,
21590                    });
21591                }
21592
21593                if chunk_lines.peek().is_some() {
21594                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21595                        line.pop_front();
21596                    }
21597                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21598                        line.pop_back();
21599                    }
21600
21601                    lines.push(mem::take(&mut line));
21602                }
21603            }
21604        }
21605
21606        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21607            return;
21608        };
21609        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21610    }
21611
21612    pub fn open_context_menu(
21613        &mut self,
21614        _: &OpenContextMenu,
21615        window: &mut Window,
21616        cx: &mut Context<Self>,
21617    ) {
21618        self.request_autoscroll(Autoscroll::newest(), cx);
21619        let position = self
21620            .selections
21621            .newest_display(&self.display_snapshot(cx))
21622            .start;
21623        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21624    }
21625
21626    pub fn replay_insert_event(
21627        &mut self,
21628        text: &str,
21629        relative_utf16_range: Option<Range<isize>>,
21630        window: &mut Window,
21631        cx: &mut Context<Self>,
21632    ) {
21633        if !self.input_enabled {
21634            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21635            return;
21636        }
21637        if let Some(relative_utf16_range) = relative_utf16_range {
21638            let selections = self
21639                .selections
21640                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21641            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21642                let new_ranges = selections.into_iter().map(|range| {
21643                    let start = OffsetUtf16(
21644                        range
21645                            .head()
21646                            .0
21647                            .saturating_add_signed(relative_utf16_range.start),
21648                    );
21649                    let end = OffsetUtf16(
21650                        range
21651                            .head()
21652                            .0
21653                            .saturating_add_signed(relative_utf16_range.end),
21654                    );
21655                    start..end
21656                });
21657                s.select_ranges(new_ranges);
21658            });
21659        }
21660
21661        self.handle_input(text, window, cx);
21662    }
21663
21664    pub fn is_focused(&self, window: &Window) -> bool {
21665        self.focus_handle.is_focused(window)
21666    }
21667
21668    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21669        cx.emit(EditorEvent::Focused);
21670
21671        if let Some(descendant) = self
21672            .last_focused_descendant
21673            .take()
21674            .and_then(|descendant| descendant.upgrade())
21675        {
21676            window.focus(&descendant);
21677        } else {
21678            if let Some(blame) = self.blame.as_ref() {
21679                blame.update(cx, GitBlame::focus)
21680            }
21681
21682            self.blink_manager.update(cx, BlinkManager::enable);
21683            self.show_cursor_names(window, cx);
21684            self.buffer.update(cx, |buffer, cx| {
21685                buffer.finalize_last_transaction(cx);
21686                if self.leader_id.is_none() {
21687                    buffer.set_active_selections(
21688                        &self.selections.disjoint_anchors_arc(),
21689                        self.selections.line_mode(),
21690                        self.cursor_shape,
21691                        cx,
21692                    );
21693                }
21694            });
21695        }
21696    }
21697
21698    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21699        cx.emit(EditorEvent::FocusedIn)
21700    }
21701
21702    fn handle_focus_out(
21703        &mut self,
21704        event: FocusOutEvent,
21705        _window: &mut Window,
21706        cx: &mut Context<Self>,
21707    ) {
21708        if event.blurred != self.focus_handle {
21709            self.last_focused_descendant = Some(event.blurred);
21710        }
21711        self.selection_drag_state = SelectionDragState::None;
21712        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21713    }
21714
21715    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21716        self.blink_manager.update(cx, BlinkManager::disable);
21717        self.buffer
21718            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21719
21720        if let Some(blame) = self.blame.as_ref() {
21721            blame.update(cx, GitBlame::blur)
21722        }
21723        if !self.hover_state.focused(window, cx) {
21724            hide_hover(self, cx);
21725        }
21726        if !self
21727            .context_menu
21728            .borrow()
21729            .as_ref()
21730            .is_some_and(|context_menu| context_menu.focused(window, cx))
21731        {
21732            self.hide_context_menu(window, cx);
21733        }
21734        self.take_active_edit_prediction(cx);
21735        cx.emit(EditorEvent::Blurred);
21736        cx.notify();
21737    }
21738
21739    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21740        let mut pending: String = window
21741            .pending_input_keystrokes()
21742            .into_iter()
21743            .flatten()
21744            .filter_map(|keystroke| {
21745                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21746                    keystroke.key_char.clone()
21747                } else {
21748                    None
21749                }
21750            })
21751            .collect();
21752
21753        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21754            pending = "".to_string();
21755        }
21756
21757        let existing_pending = self
21758            .text_highlights::<PendingInput>(cx)
21759            .map(|(_, ranges)| ranges.to_vec());
21760        if existing_pending.is_none() && pending.is_empty() {
21761            return;
21762        }
21763        let transaction =
21764            self.transact(window, cx, |this, window, cx| {
21765                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21766                let edits = selections
21767                    .iter()
21768                    .map(|selection| (selection.end..selection.end, pending.clone()));
21769                this.edit(edits, cx);
21770                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21771                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21772                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21773                    }));
21774                });
21775                if let Some(existing_ranges) = existing_pending {
21776                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21777                    this.edit(edits, cx);
21778                }
21779            });
21780
21781        let snapshot = self.snapshot(window, cx);
21782        let ranges = self
21783            .selections
21784            .all::<usize>(&snapshot.display_snapshot)
21785            .into_iter()
21786            .map(|selection| {
21787                snapshot.buffer_snapshot().anchor_after(selection.end)
21788                    ..snapshot
21789                        .buffer_snapshot()
21790                        .anchor_before(selection.end + pending.len())
21791            })
21792            .collect();
21793
21794        if pending.is_empty() {
21795            self.clear_highlights::<PendingInput>(cx);
21796        } else {
21797            self.highlight_text::<PendingInput>(
21798                ranges,
21799                HighlightStyle {
21800                    underline: Some(UnderlineStyle {
21801                        thickness: px(1.),
21802                        color: None,
21803                        wavy: false,
21804                    }),
21805                    ..Default::default()
21806                },
21807                cx,
21808            );
21809        }
21810
21811        self.ime_transaction = self.ime_transaction.or(transaction);
21812        if let Some(transaction) = self.ime_transaction {
21813            self.buffer.update(cx, |buffer, cx| {
21814                buffer.group_until_transaction(transaction, cx);
21815            });
21816        }
21817
21818        if self.text_highlights::<PendingInput>(cx).is_none() {
21819            self.ime_transaction.take();
21820        }
21821    }
21822
21823    pub fn register_action_renderer(
21824        &mut self,
21825        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21826    ) -> Subscription {
21827        let id = self.next_editor_action_id.post_inc();
21828        self.editor_actions
21829            .borrow_mut()
21830            .insert(id, Box::new(listener));
21831
21832        let editor_actions = self.editor_actions.clone();
21833        Subscription::new(move || {
21834            editor_actions.borrow_mut().remove(&id);
21835        })
21836    }
21837
21838    pub fn register_action<A: Action>(
21839        &mut self,
21840        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21841    ) -> Subscription {
21842        let id = self.next_editor_action_id.post_inc();
21843        let listener = Arc::new(listener);
21844        self.editor_actions.borrow_mut().insert(
21845            id,
21846            Box::new(move |_, window, _| {
21847                let listener = listener.clone();
21848                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21849                    let action = action.downcast_ref().unwrap();
21850                    if phase == DispatchPhase::Bubble {
21851                        listener(action, window, cx)
21852                    }
21853                })
21854            }),
21855        );
21856
21857        let editor_actions = self.editor_actions.clone();
21858        Subscription::new(move || {
21859            editor_actions.borrow_mut().remove(&id);
21860        })
21861    }
21862
21863    pub fn file_header_size(&self) -> u32 {
21864        FILE_HEADER_HEIGHT
21865    }
21866
21867    pub fn restore(
21868        &mut self,
21869        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21870        window: &mut Window,
21871        cx: &mut Context<Self>,
21872    ) {
21873        let workspace = self.workspace();
21874        let project = self.project();
21875        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21876            let mut tasks = Vec::new();
21877            for (buffer_id, changes) in revert_changes {
21878                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21879                    buffer.update(cx, |buffer, cx| {
21880                        buffer.edit(
21881                            changes
21882                                .into_iter()
21883                                .map(|(range, text)| (range, text.to_string())),
21884                            None,
21885                            cx,
21886                        );
21887                    });
21888
21889                    if let Some(project) =
21890                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21891                    {
21892                        project.update(cx, |project, cx| {
21893                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21894                        })
21895                    }
21896                }
21897            }
21898            tasks
21899        });
21900        cx.spawn_in(window, async move |_, cx| {
21901            for (buffer, task) in save_tasks {
21902                let result = task.await;
21903                if result.is_err() {
21904                    let Some(path) = buffer
21905                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21906                        .ok()
21907                    else {
21908                        continue;
21909                    };
21910                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21911                        let Some(task) = cx
21912                            .update_window_entity(workspace, |workspace, window, cx| {
21913                                workspace
21914                                    .open_path_preview(path, None, false, false, false, window, cx)
21915                            })
21916                            .ok()
21917                        else {
21918                            continue;
21919                        };
21920                        task.await.log_err();
21921                    }
21922                }
21923            }
21924        })
21925        .detach();
21926        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21927            selections.refresh()
21928        });
21929    }
21930
21931    pub fn to_pixel_point(
21932        &self,
21933        source: multi_buffer::Anchor,
21934        editor_snapshot: &EditorSnapshot,
21935        window: &mut Window,
21936    ) -> Option<gpui::Point<Pixels>> {
21937        let source_point = source.to_display_point(editor_snapshot);
21938        self.display_to_pixel_point(source_point, editor_snapshot, window)
21939    }
21940
21941    pub fn display_to_pixel_point(
21942        &self,
21943        source: DisplayPoint,
21944        editor_snapshot: &EditorSnapshot,
21945        window: &mut Window,
21946    ) -> Option<gpui::Point<Pixels>> {
21947        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21948        let text_layout_details = self.text_layout_details(window);
21949        let scroll_top = text_layout_details
21950            .scroll_anchor
21951            .scroll_position(editor_snapshot)
21952            .y;
21953
21954        if source.row().as_f64() < scroll_top.floor() {
21955            return None;
21956        }
21957        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21958        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21959        Some(gpui::Point::new(source_x, source_y))
21960    }
21961
21962    pub fn has_visible_completions_menu(&self) -> bool {
21963        !self.edit_prediction_preview_is_active()
21964            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21965                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21966            })
21967    }
21968
21969    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21970        if self.mode.is_minimap() {
21971            return;
21972        }
21973        self.addons
21974            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21975    }
21976
21977    pub fn unregister_addon<T: Addon>(&mut self) {
21978        self.addons.remove(&std::any::TypeId::of::<T>());
21979    }
21980
21981    pub fn addon<T: Addon>(&self) -> Option<&T> {
21982        let type_id = std::any::TypeId::of::<T>();
21983        self.addons
21984            .get(&type_id)
21985            .and_then(|item| item.to_any().downcast_ref::<T>())
21986    }
21987
21988    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21989        let type_id = std::any::TypeId::of::<T>();
21990        self.addons
21991            .get_mut(&type_id)
21992            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21993    }
21994
21995    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21996        let text_layout_details = self.text_layout_details(window);
21997        let style = &text_layout_details.editor_style;
21998        let font_id = window.text_system().resolve_font(&style.text.font());
21999        let font_size = style.text.font_size.to_pixels(window.rem_size());
22000        let line_height = style.text.line_height_in_pixels(window.rem_size());
22001        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22002        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22003
22004        CharacterDimensions {
22005            em_width,
22006            em_advance,
22007            line_height,
22008        }
22009    }
22010
22011    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22012        self.load_diff_task.clone()
22013    }
22014
22015    fn read_metadata_from_db(
22016        &mut self,
22017        item_id: u64,
22018        workspace_id: WorkspaceId,
22019        window: &mut Window,
22020        cx: &mut Context<Editor>,
22021    ) {
22022        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22023            && !self.mode.is_minimap()
22024            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22025        {
22026            let buffer_snapshot = OnceCell::new();
22027
22028            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22029                && !folds.is_empty()
22030            {
22031                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22032                self.fold_ranges(
22033                    folds
22034                        .into_iter()
22035                        .map(|(start, end)| {
22036                            snapshot.clip_offset(start, Bias::Left)
22037                                ..snapshot.clip_offset(end, Bias::Right)
22038                        })
22039                        .collect(),
22040                    false,
22041                    window,
22042                    cx,
22043                );
22044            }
22045
22046            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22047                && !selections.is_empty()
22048            {
22049                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22050                // skip adding the initial selection to selection history
22051                self.selection_history.mode = SelectionHistoryMode::Skipping;
22052                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22053                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22054                        snapshot.clip_offset(start, Bias::Left)
22055                            ..snapshot.clip_offset(end, Bias::Right)
22056                    }));
22057                });
22058                self.selection_history.mode = SelectionHistoryMode::Normal;
22059            };
22060        }
22061
22062        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22063    }
22064
22065    fn update_lsp_data(
22066        &mut self,
22067        for_buffer: Option<BufferId>,
22068        window: &mut Window,
22069        cx: &mut Context<'_, Self>,
22070    ) {
22071        self.pull_diagnostics(for_buffer, window, cx);
22072        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22073    }
22074
22075    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22076        if self.ignore_lsp_data() {
22077            return;
22078        }
22079        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22080            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22081        }
22082    }
22083
22084    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22085        if !self.registered_buffers.contains_key(&buffer_id)
22086            && let Some(project) = self.project.as_ref()
22087        {
22088            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22089                project.update(cx, |project, cx| {
22090                    self.registered_buffers.insert(
22091                        buffer_id,
22092                        project.register_buffer_with_language_servers(&buffer, cx),
22093                    );
22094                });
22095            } else {
22096                self.registered_buffers.remove(&buffer_id);
22097            }
22098        }
22099    }
22100
22101    fn ignore_lsp_data(&self) -> bool {
22102        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22103        // skip any LSP updates for it.
22104        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22105    }
22106}
22107
22108fn edit_for_markdown_paste<'a>(
22109    buffer: &MultiBufferSnapshot,
22110    range: Range<usize>,
22111    to_insert: &'a str,
22112    url: Option<url::Url>,
22113) -> (Range<usize>, Cow<'a, str>) {
22114    if url.is_none() {
22115        return (range, Cow::Borrowed(to_insert));
22116    };
22117
22118    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22119
22120    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22121        Cow::Borrowed(to_insert)
22122    } else {
22123        Cow::Owned(format!("[{old_text}]({to_insert})"))
22124    };
22125    (range, new_text)
22126}
22127
22128#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22129pub enum VimFlavor {
22130    Vim,
22131    Helix,
22132}
22133
22134pub fn vim_flavor(cx: &App) -> Option<VimFlavor> {
22135    if vim_mode_setting::HelixModeSetting::try_get(cx)
22136        .map(|helix_mode| helix_mode.0)
22137        .unwrap_or(false)
22138    {
22139        Some(VimFlavor::Helix)
22140    } else if vim_mode_setting::VimModeSetting::try_get(cx)
22141        .map(|vim_mode| vim_mode.0)
22142        .unwrap_or(false)
22143    {
22144        Some(VimFlavor::Vim)
22145    } else {
22146        None // neither vim nor helix mode
22147    }
22148}
22149
22150fn process_completion_for_edit(
22151    completion: &Completion,
22152    intent: CompletionIntent,
22153    buffer: &Entity<Buffer>,
22154    cursor_position: &text::Anchor,
22155    cx: &mut Context<Editor>,
22156) -> CompletionEdit {
22157    let buffer = buffer.read(cx);
22158    let buffer_snapshot = buffer.snapshot();
22159    let (snippet, new_text) = if completion.is_snippet() {
22160        let mut snippet_source = completion.new_text.clone();
22161        // Workaround for typescript language server issues so that methods don't expand within
22162        // strings and functions with type expressions. The previous point is used because the query
22163        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22164        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22165        let previous_point = if previous_point.column > 0 {
22166            cursor_position.to_previous_offset(&buffer_snapshot)
22167        } else {
22168            cursor_position.to_offset(&buffer_snapshot)
22169        };
22170        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22171            && scope.prefers_label_for_snippet_in_completion()
22172            && let Some(label) = completion.label()
22173            && matches!(
22174                completion.kind(),
22175                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22176            )
22177        {
22178            snippet_source = label;
22179        }
22180        match Snippet::parse(&snippet_source).log_err() {
22181            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22182            None => (None, completion.new_text.clone()),
22183        }
22184    } else {
22185        (None, completion.new_text.clone())
22186    };
22187
22188    let mut range_to_replace = {
22189        let replace_range = &completion.replace_range;
22190        if let CompletionSource::Lsp {
22191            insert_range: Some(insert_range),
22192            ..
22193        } = &completion.source
22194        {
22195            debug_assert_eq!(
22196                insert_range.start, replace_range.start,
22197                "insert_range and replace_range should start at the same position"
22198            );
22199            debug_assert!(
22200                insert_range
22201                    .start
22202                    .cmp(cursor_position, &buffer_snapshot)
22203                    .is_le(),
22204                "insert_range should start before or at cursor position"
22205            );
22206            debug_assert!(
22207                replace_range
22208                    .start
22209                    .cmp(cursor_position, &buffer_snapshot)
22210                    .is_le(),
22211                "replace_range should start before or at cursor position"
22212            );
22213
22214            let should_replace = match intent {
22215                CompletionIntent::CompleteWithInsert => false,
22216                CompletionIntent::CompleteWithReplace => true,
22217                CompletionIntent::Complete | CompletionIntent::Compose => {
22218                    let insert_mode =
22219                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22220                            .completions
22221                            .lsp_insert_mode;
22222                    match insert_mode {
22223                        LspInsertMode::Insert => false,
22224                        LspInsertMode::Replace => true,
22225                        LspInsertMode::ReplaceSubsequence => {
22226                            let mut text_to_replace = buffer.chars_for_range(
22227                                buffer.anchor_before(replace_range.start)
22228                                    ..buffer.anchor_after(replace_range.end),
22229                            );
22230                            let mut current_needle = text_to_replace.next();
22231                            for haystack_ch in completion.label.text.chars() {
22232                                if let Some(needle_ch) = current_needle
22233                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22234                                {
22235                                    current_needle = text_to_replace.next();
22236                                }
22237                            }
22238                            current_needle.is_none()
22239                        }
22240                        LspInsertMode::ReplaceSuffix => {
22241                            if replace_range
22242                                .end
22243                                .cmp(cursor_position, &buffer_snapshot)
22244                                .is_gt()
22245                            {
22246                                let range_after_cursor = *cursor_position..replace_range.end;
22247                                let text_after_cursor = buffer
22248                                    .text_for_range(
22249                                        buffer.anchor_before(range_after_cursor.start)
22250                                            ..buffer.anchor_after(range_after_cursor.end),
22251                                    )
22252                                    .collect::<String>()
22253                                    .to_ascii_lowercase();
22254                                completion
22255                                    .label
22256                                    .text
22257                                    .to_ascii_lowercase()
22258                                    .ends_with(&text_after_cursor)
22259                            } else {
22260                                true
22261                            }
22262                        }
22263                    }
22264                }
22265            };
22266
22267            if should_replace {
22268                replace_range.clone()
22269            } else {
22270                insert_range.clone()
22271            }
22272        } else {
22273            replace_range.clone()
22274        }
22275    };
22276
22277    if range_to_replace
22278        .end
22279        .cmp(cursor_position, &buffer_snapshot)
22280        .is_lt()
22281    {
22282        range_to_replace.end = *cursor_position;
22283    }
22284
22285    CompletionEdit {
22286        new_text,
22287        replace_range: range_to_replace.to_offset(buffer),
22288        snippet,
22289    }
22290}
22291
22292struct CompletionEdit {
22293    new_text: String,
22294    replace_range: Range<usize>,
22295    snippet: Option<Snippet>,
22296}
22297
22298fn insert_extra_newline_brackets(
22299    buffer: &MultiBufferSnapshot,
22300    range: Range<usize>,
22301    language: &language::LanguageScope,
22302) -> bool {
22303    let leading_whitespace_len = buffer
22304        .reversed_chars_at(range.start)
22305        .take_while(|c| c.is_whitespace() && *c != '\n')
22306        .map(|c| c.len_utf8())
22307        .sum::<usize>();
22308    let trailing_whitespace_len = buffer
22309        .chars_at(range.end)
22310        .take_while(|c| c.is_whitespace() && *c != '\n')
22311        .map(|c| c.len_utf8())
22312        .sum::<usize>();
22313    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22314
22315    language.brackets().any(|(pair, enabled)| {
22316        let pair_start = pair.start.trim_end();
22317        let pair_end = pair.end.trim_start();
22318
22319        enabled
22320            && pair.newline
22321            && buffer.contains_str_at(range.end, pair_end)
22322            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22323    })
22324}
22325
22326fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22327    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22328        [(buffer, range, _)] => (*buffer, range.clone()),
22329        _ => return false,
22330    };
22331    let pair = {
22332        let mut result: Option<BracketMatch> = None;
22333
22334        for pair in buffer
22335            .all_bracket_ranges(range.clone())
22336            .filter(move |pair| {
22337                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22338            })
22339        {
22340            let len = pair.close_range.end - pair.open_range.start;
22341
22342            if let Some(existing) = &result {
22343                let existing_len = existing.close_range.end - existing.open_range.start;
22344                if len > existing_len {
22345                    continue;
22346                }
22347            }
22348
22349            result = Some(pair);
22350        }
22351
22352        result
22353    };
22354    let Some(pair) = pair else {
22355        return false;
22356    };
22357    pair.newline_only
22358        && buffer
22359            .chars_for_range(pair.open_range.end..range.start)
22360            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22361            .all(|c| c.is_whitespace() && c != '\n')
22362}
22363
22364fn update_uncommitted_diff_for_buffer(
22365    editor: Entity<Editor>,
22366    project: &Entity<Project>,
22367    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22368    buffer: Entity<MultiBuffer>,
22369    cx: &mut App,
22370) -> Task<()> {
22371    let mut tasks = Vec::new();
22372    project.update(cx, |project, cx| {
22373        for buffer in buffers {
22374            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22375                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22376            }
22377        }
22378    });
22379    cx.spawn(async move |cx| {
22380        let diffs = future::join_all(tasks).await;
22381        if editor
22382            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22383            .unwrap_or(false)
22384        {
22385            return;
22386        }
22387
22388        buffer
22389            .update(cx, |buffer, cx| {
22390                for diff in diffs.into_iter().flatten() {
22391                    buffer.add_diff(diff, cx);
22392                }
22393            })
22394            .ok();
22395    })
22396}
22397
22398fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22399    let tab_size = tab_size.get() as usize;
22400    let mut width = offset;
22401
22402    for ch in text.chars() {
22403        width += if ch == '\t' {
22404            tab_size - (width % tab_size)
22405        } else {
22406            1
22407        };
22408    }
22409
22410    width - offset
22411}
22412
22413#[cfg(test)]
22414mod tests {
22415    use super::*;
22416
22417    #[test]
22418    fn test_string_size_with_expanded_tabs() {
22419        let nz = |val| NonZeroU32::new(val).unwrap();
22420        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22421        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22422        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22423        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22424        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22425        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22426        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22427        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22428    }
22429}
22430
22431/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22432struct WordBreakingTokenizer<'a> {
22433    input: &'a str,
22434}
22435
22436impl<'a> WordBreakingTokenizer<'a> {
22437    fn new(input: &'a str) -> Self {
22438        Self { input }
22439    }
22440}
22441
22442fn is_char_ideographic(ch: char) -> bool {
22443    use unicode_script::Script::*;
22444    use unicode_script::UnicodeScript;
22445    matches!(ch.script(), Han | Tangut | Yi)
22446}
22447
22448fn is_grapheme_ideographic(text: &str) -> bool {
22449    text.chars().any(is_char_ideographic)
22450}
22451
22452fn is_grapheme_whitespace(text: &str) -> bool {
22453    text.chars().any(|x| x.is_whitespace())
22454}
22455
22456fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22457    text.chars()
22458        .next()
22459        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22460}
22461
22462#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22463enum WordBreakToken<'a> {
22464    Word { token: &'a str, grapheme_len: usize },
22465    InlineWhitespace { token: &'a str, grapheme_len: usize },
22466    Newline,
22467}
22468
22469impl<'a> Iterator for WordBreakingTokenizer<'a> {
22470    /// Yields a span, the count of graphemes in the token, and whether it was
22471    /// whitespace. Note that it also breaks at word boundaries.
22472    type Item = WordBreakToken<'a>;
22473
22474    fn next(&mut self) -> Option<Self::Item> {
22475        use unicode_segmentation::UnicodeSegmentation;
22476        if self.input.is_empty() {
22477            return None;
22478        }
22479
22480        let mut iter = self.input.graphemes(true).peekable();
22481        let mut offset = 0;
22482        let mut grapheme_len = 0;
22483        if let Some(first_grapheme) = iter.next() {
22484            let is_newline = first_grapheme == "\n";
22485            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22486            offset += first_grapheme.len();
22487            grapheme_len += 1;
22488            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22489                if let Some(grapheme) = iter.peek().copied()
22490                    && should_stay_with_preceding_ideograph(grapheme)
22491                {
22492                    offset += grapheme.len();
22493                    grapheme_len += 1;
22494                }
22495            } else {
22496                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22497                let mut next_word_bound = words.peek().copied();
22498                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22499                    next_word_bound = words.next();
22500                }
22501                while let Some(grapheme) = iter.peek().copied() {
22502                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22503                        break;
22504                    };
22505                    if is_grapheme_whitespace(grapheme) != is_whitespace
22506                        || (grapheme == "\n") != is_newline
22507                    {
22508                        break;
22509                    };
22510                    offset += grapheme.len();
22511                    grapheme_len += 1;
22512                    iter.next();
22513                }
22514            }
22515            let token = &self.input[..offset];
22516            self.input = &self.input[offset..];
22517            if token == "\n" {
22518                Some(WordBreakToken::Newline)
22519            } else if is_whitespace {
22520                Some(WordBreakToken::InlineWhitespace {
22521                    token,
22522                    grapheme_len,
22523                })
22524            } else {
22525                Some(WordBreakToken::Word {
22526                    token,
22527                    grapheme_len,
22528                })
22529            }
22530        } else {
22531            None
22532        }
22533    }
22534}
22535
22536#[test]
22537fn test_word_breaking_tokenizer() {
22538    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22539        ("", &[]),
22540        ("  ", &[whitespace("  ", 2)]),
22541        ("Ʒ", &[word("Ʒ", 1)]),
22542        ("Ǽ", &[word("Ǽ", 1)]),
22543        ("", &[word("", 1)]),
22544        ("⋑⋑", &[word("⋑⋑", 2)]),
22545        (
22546            "原理,进而",
22547            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22548        ),
22549        (
22550            "hello world",
22551            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22552        ),
22553        (
22554            "hello, world",
22555            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22556        ),
22557        (
22558            "  hello world",
22559            &[
22560                whitespace("  ", 2),
22561                word("hello", 5),
22562                whitespace(" ", 1),
22563                word("world", 5),
22564            ],
22565        ),
22566        (
22567            "这是什么 \n 钢笔",
22568            &[
22569                word("", 1),
22570                word("", 1),
22571                word("", 1),
22572                word("", 1),
22573                whitespace(" ", 1),
22574                newline(),
22575                whitespace(" ", 1),
22576                word("", 1),
22577                word("", 1),
22578            ],
22579        ),
22580        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22581    ];
22582
22583    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22584        WordBreakToken::Word {
22585            token,
22586            grapheme_len,
22587        }
22588    }
22589
22590    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22591        WordBreakToken::InlineWhitespace {
22592            token,
22593            grapheme_len,
22594        }
22595    }
22596
22597    fn newline() -> WordBreakToken<'static> {
22598        WordBreakToken::Newline
22599    }
22600
22601    for (input, result) in tests {
22602        assert_eq!(
22603            WordBreakingTokenizer::new(input)
22604                .collect::<Vec<_>>()
22605                .as_slice(),
22606            *result,
22607        );
22608    }
22609}
22610
22611fn wrap_with_prefix(
22612    first_line_prefix: String,
22613    subsequent_lines_prefix: String,
22614    unwrapped_text: String,
22615    wrap_column: usize,
22616    tab_size: NonZeroU32,
22617    preserve_existing_whitespace: bool,
22618) -> String {
22619    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22620    let subsequent_lines_prefix_len =
22621        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22622    let mut wrapped_text = String::new();
22623    let mut current_line = first_line_prefix;
22624    let mut is_first_line = true;
22625
22626    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22627    let mut current_line_len = first_line_prefix_len;
22628    let mut in_whitespace = false;
22629    for token in tokenizer {
22630        let have_preceding_whitespace = in_whitespace;
22631        match token {
22632            WordBreakToken::Word {
22633                token,
22634                grapheme_len,
22635            } => {
22636                in_whitespace = false;
22637                let current_prefix_len = if is_first_line {
22638                    first_line_prefix_len
22639                } else {
22640                    subsequent_lines_prefix_len
22641                };
22642                if current_line_len + grapheme_len > wrap_column
22643                    && current_line_len != current_prefix_len
22644                {
22645                    wrapped_text.push_str(current_line.trim_end());
22646                    wrapped_text.push('\n');
22647                    is_first_line = false;
22648                    current_line = subsequent_lines_prefix.clone();
22649                    current_line_len = subsequent_lines_prefix_len;
22650                }
22651                current_line.push_str(token);
22652                current_line_len += grapheme_len;
22653            }
22654            WordBreakToken::InlineWhitespace {
22655                mut token,
22656                mut grapheme_len,
22657            } => {
22658                in_whitespace = true;
22659                if have_preceding_whitespace && !preserve_existing_whitespace {
22660                    continue;
22661                }
22662                if !preserve_existing_whitespace {
22663                    // Keep a single whitespace grapheme as-is
22664                    if let Some(first) =
22665                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22666                    {
22667                        token = first;
22668                    } else {
22669                        token = " ";
22670                    }
22671                    grapheme_len = 1;
22672                }
22673                let current_prefix_len = if is_first_line {
22674                    first_line_prefix_len
22675                } else {
22676                    subsequent_lines_prefix_len
22677                };
22678                if current_line_len + grapheme_len > wrap_column {
22679                    wrapped_text.push_str(current_line.trim_end());
22680                    wrapped_text.push('\n');
22681                    is_first_line = false;
22682                    current_line = subsequent_lines_prefix.clone();
22683                    current_line_len = subsequent_lines_prefix_len;
22684                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22685                    current_line.push_str(token);
22686                    current_line_len += grapheme_len;
22687                }
22688            }
22689            WordBreakToken::Newline => {
22690                in_whitespace = true;
22691                let current_prefix_len = if is_first_line {
22692                    first_line_prefix_len
22693                } else {
22694                    subsequent_lines_prefix_len
22695                };
22696                if preserve_existing_whitespace {
22697                    wrapped_text.push_str(current_line.trim_end());
22698                    wrapped_text.push('\n');
22699                    is_first_line = false;
22700                    current_line = subsequent_lines_prefix.clone();
22701                    current_line_len = subsequent_lines_prefix_len;
22702                } else if have_preceding_whitespace {
22703                    continue;
22704                } else if current_line_len + 1 > wrap_column
22705                    && current_line_len != current_prefix_len
22706                {
22707                    wrapped_text.push_str(current_line.trim_end());
22708                    wrapped_text.push('\n');
22709                    is_first_line = false;
22710                    current_line = subsequent_lines_prefix.clone();
22711                    current_line_len = subsequent_lines_prefix_len;
22712                } else if current_line_len != current_prefix_len {
22713                    current_line.push(' ');
22714                    current_line_len += 1;
22715                }
22716            }
22717        }
22718    }
22719
22720    if !current_line.is_empty() {
22721        wrapped_text.push_str(&current_line);
22722    }
22723    wrapped_text
22724}
22725
22726#[test]
22727fn test_wrap_with_prefix() {
22728    assert_eq!(
22729        wrap_with_prefix(
22730            "# ".to_string(),
22731            "# ".to_string(),
22732            "abcdefg".to_string(),
22733            4,
22734            NonZeroU32::new(4).unwrap(),
22735            false,
22736        ),
22737        "# abcdefg"
22738    );
22739    assert_eq!(
22740        wrap_with_prefix(
22741            "".to_string(),
22742            "".to_string(),
22743            "\thello world".to_string(),
22744            8,
22745            NonZeroU32::new(4).unwrap(),
22746            false,
22747        ),
22748        "hello\nworld"
22749    );
22750    assert_eq!(
22751        wrap_with_prefix(
22752            "// ".to_string(),
22753            "// ".to_string(),
22754            "xx \nyy zz aa bb cc".to_string(),
22755            12,
22756            NonZeroU32::new(4).unwrap(),
22757            false,
22758        ),
22759        "// xx yy zz\n// aa bb cc"
22760    );
22761    assert_eq!(
22762        wrap_with_prefix(
22763            String::new(),
22764            String::new(),
22765            "这是什么 \n 钢笔".to_string(),
22766            3,
22767            NonZeroU32::new(4).unwrap(),
22768            false,
22769        ),
22770        "这是什\n么 钢\n"
22771    );
22772    assert_eq!(
22773        wrap_with_prefix(
22774            String::new(),
22775            String::new(),
22776            format!("foo{}bar", '\u{2009}'), // thin space
22777            80,
22778            NonZeroU32::new(4).unwrap(),
22779            false,
22780        ),
22781        format!("foo{}bar", '\u{2009}')
22782    );
22783}
22784
22785pub trait CollaborationHub {
22786    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22787    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22788    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22789}
22790
22791impl CollaborationHub for Entity<Project> {
22792    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22793        self.read(cx).collaborators()
22794    }
22795
22796    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22797        self.read(cx).user_store().read(cx).participant_indices()
22798    }
22799
22800    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22801        let this = self.read(cx);
22802        let user_ids = this.collaborators().values().map(|c| c.user_id);
22803        this.user_store().read(cx).participant_names(user_ids, cx)
22804    }
22805}
22806
22807pub trait SemanticsProvider {
22808    fn hover(
22809        &self,
22810        buffer: &Entity<Buffer>,
22811        position: text::Anchor,
22812        cx: &mut App,
22813    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22814
22815    fn inline_values(
22816        &self,
22817        buffer_handle: Entity<Buffer>,
22818        range: Range<text::Anchor>,
22819        cx: &mut App,
22820    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22821
22822    fn applicable_inlay_chunks(
22823        &self,
22824        buffer: &Entity<Buffer>,
22825        ranges: &[Range<text::Anchor>],
22826        cx: &mut App,
22827    ) -> Vec<Range<BufferRow>>;
22828
22829    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22830
22831    fn inlay_hints(
22832        &self,
22833        invalidate: InvalidationStrategy,
22834        buffer: Entity<Buffer>,
22835        ranges: Vec<Range<text::Anchor>>,
22836        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22837        cx: &mut App,
22838    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22839
22840    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22841
22842    fn document_highlights(
22843        &self,
22844        buffer: &Entity<Buffer>,
22845        position: text::Anchor,
22846        cx: &mut App,
22847    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22848
22849    fn definitions(
22850        &self,
22851        buffer: &Entity<Buffer>,
22852        position: text::Anchor,
22853        kind: GotoDefinitionKind,
22854        cx: &mut App,
22855    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22856
22857    fn range_for_rename(
22858        &self,
22859        buffer: &Entity<Buffer>,
22860        position: text::Anchor,
22861        cx: &mut App,
22862    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22863
22864    fn perform_rename(
22865        &self,
22866        buffer: &Entity<Buffer>,
22867        position: text::Anchor,
22868        new_name: String,
22869        cx: &mut App,
22870    ) -> Option<Task<Result<ProjectTransaction>>>;
22871}
22872
22873pub trait CompletionProvider {
22874    fn completions(
22875        &self,
22876        excerpt_id: ExcerptId,
22877        buffer: &Entity<Buffer>,
22878        buffer_position: text::Anchor,
22879        trigger: CompletionContext,
22880        window: &mut Window,
22881        cx: &mut Context<Editor>,
22882    ) -> Task<Result<Vec<CompletionResponse>>>;
22883
22884    fn resolve_completions(
22885        &self,
22886        _buffer: Entity<Buffer>,
22887        _completion_indices: Vec<usize>,
22888        _completions: Rc<RefCell<Box<[Completion]>>>,
22889        _cx: &mut Context<Editor>,
22890    ) -> Task<Result<bool>> {
22891        Task::ready(Ok(false))
22892    }
22893
22894    fn apply_additional_edits_for_completion(
22895        &self,
22896        _buffer: Entity<Buffer>,
22897        _completions: Rc<RefCell<Box<[Completion]>>>,
22898        _completion_index: usize,
22899        _push_to_history: bool,
22900        _cx: &mut Context<Editor>,
22901    ) -> Task<Result<Option<language::Transaction>>> {
22902        Task::ready(Ok(None))
22903    }
22904
22905    fn is_completion_trigger(
22906        &self,
22907        buffer: &Entity<Buffer>,
22908        position: language::Anchor,
22909        text: &str,
22910        trigger_in_words: bool,
22911        menu_is_open: bool,
22912        cx: &mut Context<Editor>,
22913    ) -> bool;
22914
22915    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22916
22917    fn sort_completions(&self) -> bool {
22918        true
22919    }
22920
22921    fn filter_completions(&self) -> bool {
22922        true
22923    }
22924}
22925
22926pub trait CodeActionProvider {
22927    fn id(&self) -> Arc<str>;
22928
22929    fn code_actions(
22930        &self,
22931        buffer: &Entity<Buffer>,
22932        range: Range<text::Anchor>,
22933        window: &mut Window,
22934        cx: &mut App,
22935    ) -> Task<Result<Vec<CodeAction>>>;
22936
22937    fn apply_code_action(
22938        &self,
22939        buffer_handle: Entity<Buffer>,
22940        action: CodeAction,
22941        excerpt_id: ExcerptId,
22942        push_to_history: bool,
22943        window: &mut Window,
22944        cx: &mut App,
22945    ) -> Task<Result<ProjectTransaction>>;
22946}
22947
22948impl CodeActionProvider for Entity<Project> {
22949    fn id(&self) -> Arc<str> {
22950        "project".into()
22951    }
22952
22953    fn code_actions(
22954        &self,
22955        buffer: &Entity<Buffer>,
22956        range: Range<text::Anchor>,
22957        _window: &mut Window,
22958        cx: &mut App,
22959    ) -> Task<Result<Vec<CodeAction>>> {
22960        self.update(cx, |project, cx| {
22961            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22962            let code_actions = project.code_actions(buffer, range, None, cx);
22963            cx.background_spawn(async move {
22964                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22965                Ok(code_lens_actions
22966                    .context("code lens fetch")?
22967                    .into_iter()
22968                    .flatten()
22969                    .chain(
22970                        code_actions
22971                            .context("code action fetch")?
22972                            .into_iter()
22973                            .flatten(),
22974                    )
22975                    .collect())
22976            })
22977        })
22978    }
22979
22980    fn apply_code_action(
22981        &self,
22982        buffer_handle: Entity<Buffer>,
22983        action: CodeAction,
22984        _excerpt_id: ExcerptId,
22985        push_to_history: bool,
22986        _window: &mut Window,
22987        cx: &mut App,
22988    ) -> Task<Result<ProjectTransaction>> {
22989        self.update(cx, |project, cx| {
22990            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22991        })
22992    }
22993}
22994
22995fn snippet_completions(
22996    project: &Project,
22997    buffer: &Entity<Buffer>,
22998    buffer_position: text::Anchor,
22999    cx: &mut App,
23000) -> Task<Result<CompletionResponse>> {
23001    let languages = buffer.read(cx).languages_at(buffer_position);
23002    let snippet_store = project.snippets().read(cx);
23003
23004    let scopes: Vec<_> = languages
23005        .iter()
23006        .filter_map(|language| {
23007            let language_name = language.lsp_id();
23008            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23009
23010            if snippets.is_empty() {
23011                None
23012            } else {
23013                Some((language.default_scope(), snippets))
23014            }
23015        })
23016        .collect();
23017
23018    if scopes.is_empty() {
23019        return Task::ready(Ok(CompletionResponse {
23020            completions: vec![],
23021            display_options: CompletionDisplayOptions::default(),
23022            is_incomplete: false,
23023        }));
23024    }
23025
23026    let snapshot = buffer.read(cx).text_snapshot();
23027    let executor = cx.background_executor().clone();
23028
23029    cx.background_spawn(async move {
23030        let mut is_incomplete = false;
23031        let mut completions: Vec<Completion> = Vec::new();
23032        for (scope, snippets) in scopes.into_iter() {
23033            let classifier =
23034                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
23035
23036            const MAX_WORD_PREFIX_LEN: usize = 128;
23037            let last_word: String = snapshot
23038                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
23039                .take(MAX_WORD_PREFIX_LEN)
23040                .take_while(|c| classifier.is_word(*c))
23041                .collect::<String>()
23042                .chars()
23043                .rev()
23044                .collect();
23045
23046            if last_word.is_empty() {
23047                return Ok(CompletionResponse {
23048                    completions: vec![],
23049                    display_options: CompletionDisplayOptions::default(),
23050                    is_incomplete: true,
23051                });
23052            }
23053
23054            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23055            let to_lsp = |point: &text::Anchor| {
23056                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23057                point_to_lsp(end)
23058            };
23059            let lsp_end = to_lsp(&buffer_position);
23060
23061            let candidates = snippets
23062                .iter()
23063                .enumerate()
23064                .flat_map(|(ix, snippet)| {
23065                    snippet
23066                        .prefix
23067                        .iter()
23068                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23069                })
23070                .collect::<Vec<StringMatchCandidate>>();
23071
23072            const MAX_RESULTS: usize = 100;
23073            let mut matches = fuzzy::match_strings(
23074                &candidates,
23075                &last_word,
23076                last_word.chars().any(|c| c.is_uppercase()),
23077                true,
23078                MAX_RESULTS,
23079                &Default::default(),
23080                executor.clone(),
23081            )
23082            .await;
23083
23084            if matches.len() >= MAX_RESULTS {
23085                is_incomplete = true;
23086            }
23087
23088            // Remove all candidates where the query's start does not match the start of any word in the candidate
23089            if let Some(query_start) = last_word.chars().next() {
23090                matches.retain(|string_match| {
23091                    split_words(&string_match.string).any(|word| {
23092                        // Check that the first codepoint of the word as lowercase matches the first
23093                        // codepoint of the query as lowercase
23094                        word.chars()
23095                            .flat_map(|codepoint| codepoint.to_lowercase())
23096                            .zip(query_start.to_lowercase())
23097                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23098                    })
23099                });
23100            }
23101
23102            let matched_strings = matches
23103                .into_iter()
23104                .map(|m| m.string)
23105                .collect::<HashSet<_>>();
23106
23107            completions.extend(snippets.iter().filter_map(|snippet| {
23108                let matching_prefix = snippet
23109                    .prefix
23110                    .iter()
23111                    .find(|prefix| matched_strings.contains(*prefix))?;
23112                let start = as_offset - last_word.len();
23113                let start = snapshot.anchor_before(start);
23114                let range = start..buffer_position;
23115                let lsp_start = to_lsp(&start);
23116                let lsp_range = lsp::Range {
23117                    start: lsp_start,
23118                    end: lsp_end,
23119                };
23120                Some(Completion {
23121                    replace_range: range,
23122                    new_text: snippet.body.clone(),
23123                    source: CompletionSource::Lsp {
23124                        insert_range: None,
23125                        server_id: LanguageServerId(usize::MAX),
23126                        resolved: true,
23127                        lsp_completion: Box::new(lsp::CompletionItem {
23128                            label: snippet.prefix.first().unwrap().clone(),
23129                            kind: Some(CompletionItemKind::SNIPPET),
23130                            label_details: snippet.description.as_ref().map(|description| {
23131                                lsp::CompletionItemLabelDetails {
23132                                    detail: Some(description.clone()),
23133                                    description: None,
23134                                }
23135                            }),
23136                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23137                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23138                                lsp::InsertReplaceEdit {
23139                                    new_text: snippet.body.clone(),
23140                                    insert: lsp_range,
23141                                    replace: lsp_range,
23142                                },
23143                            )),
23144                            filter_text: Some(snippet.body.clone()),
23145                            sort_text: Some(char::MAX.to_string()),
23146                            ..lsp::CompletionItem::default()
23147                        }),
23148                        lsp_defaults: None,
23149                    },
23150                    label: CodeLabel::plain(matching_prefix.clone(), None),
23151                    icon_path: None,
23152                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23153                        single_line: snippet.name.clone().into(),
23154                        plain_text: snippet
23155                            .description
23156                            .clone()
23157                            .map(|description| description.into()),
23158                    }),
23159                    insert_text_mode: None,
23160                    confirm: None,
23161                })
23162            }))
23163        }
23164
23165        Ok(CompletionResponse {
23166            completions,
23167            display_options: CompletionDisplayOptions::default(),
23168            is_incomplete,
23169        })
23170    })
23171}
23172
23173impl CompletionProvider for Entity<Project> {
23174    fn completions(
23175        &self,
23176        _excerpt_id: ExcerptId,
23177        buffer: &Entity<Buffer>,
23178        buffer_position: text::Anchor,
23179        options: CompletionContext,
23180        _window: &mut Window,
23181        cx: &mut Context<Editor>,
23182    ) -> Task<Result<Vec<CompletionResponse>>> {
23183        self.update(cx, |project, cx| {
23184            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23185            let project_completions = project.completions(buffer, buffer_position, options, cx);
23186            cx.background_spawn(async move {
23187                let mut responses = project_completions.await?;
23188                let snippets = snippets.await?;
23189                if !snippets.completions.is_empty() {
23190                    responses.push(snippets);
23191                }
23192                Ok(responses)
23193            })
23194        })
23195    }
23196
23197    fn resolve_completions(
23198        &self,
23199        buffer: Entity<Buffer>,
23200        completion_indices: Vec<usize>,
23201        completions: Rc<RefCell<Box<[Completion]>>>,
23202        cx: &mut Context<Editor>,
23203    ) -> Task<Result<bool>> {
23204        self.update(cx, |project, cx| {
23205            project.lsp_store().update(cx, |lsp_store, cx| {
23206                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23207            })
23208        })
23209    }
23210
23211    fn apply_additional_edits_for_completion(
23212        &self,
23213        buffer: Entity<Buffer>,
23214        completions: Rc<RefCell<Box<[Completion]>>>,
23215        completion_index: usize,
23216        push_to_history: bool,
23217        cx: &mut Context<Editor>,
23218    ) -> Task<Result<Option<language::Transaction>>> {
23219        self.update(cx, |project, cx| {
23220            project.lsp_store().update(cx, |lsp_store, cx| {
23221                lsp_store.apply_additional_edits_for_completion(
23222                    buffer,
23223                    completions,
23224                    completion_index,
23225                    push_to_history,
23226                    cx,
23227                )
23228            })
23229        })
23230    }
23231
23232    fn is_completion_trigger(
23233        &self,
23234        buffer: &Entity<Buffer>,
23235        position: language::Anchor,
23236        text: &str,
23237        trigger_in_words: bool,
23238        menu_is_open: bool,
23239        cx: &mut Context<Editor>,
23240    ) -> bool {
23241        let mut chars = text.chars();
23242        let char = if let Some(char) = chars.next() {
23243            char
23244        } else {
23245            return false;
23246        };
23247        if chars.next().is_some() {
23248            return false;
23249        }
23250
23251        let buffer = buffer.read(cx);
23252        let snapshot = buffer.snapshot();
23253        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23254            return false;
23255        }
23256        let classifier = snapshot
23257            .char_classifier_at(position)
23258            .scope_context(Some(CharScopeContext::Completion));
23259        if trigger_in_words && classifier.is_word(char) {
23260            return true;
23261        }
23262
23263        buffer.completion_triggers().contains(text)
23264    }
23265}
23266
23267impl SemanticsProvider for Entity<Project> {
23268    fn hover(
23269        &self,
23270        buffer: &Entity<Buffer>,
23271        position: text::Anchor,
23272        cx: &mut App,
23273    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23274        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23275    }
23276
23277    fn document_highlights(
23278        &self,
23279        buffer: &Entity<Buffer>,
23280        position: text::Anchor,
23281        cx: &mut App,
23282    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23283        Some(self.update(cx, |project, cx| {
23284            project.document_highlights(buffer, position, cx)
23285        }))
23286    }
23287
23288    fn definitions(
23289        &self,
23290        buffer: &Entity<Buffer>,
23291        position: text::Anchor,
23292        kind: GotoDefinitionKind,
23293        cx: &mut App,
23294    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23295        Some(self.update(cx, |project, cx| match kind {
23296            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23297            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23298            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23299            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23300        }))
23301    }
23302
23303    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23304        self.update(cx, |project, cx| {
23305            if project
23306                .active_debug_session(cx)
23307                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23308            {
23309                return true;
23310            }
23311
23312            buffer.update(cx, |buffer, cx| {
23313                project.any_language_server_supports_inlay_hints(buffer, cx)
23314            })
23315        })
23316    }
23317
23318    fn inline_values(
23319        &self,
23320        buffer_handle: Entity<Buffer>,
23321        range: Range<text::Anchor>,
23322        cx: &mut App,
23323    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23324        self.update(cx, |project, cx| {
23325            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23326
23327            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23328        })
23329    }
23330
23331    fn applicable_inlay_chunks(
23332        &self,
23333        buffer: &Entity<Buffer>,
23334        ranges: &[Range<text::Anchor>],
23335        cx: &mut App,
23336    ) -> Vec<Range<BufferRow>> {
23337        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23338            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23339        })
23340    }
23341
23342    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23343        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23344            lsp_store.invalidate_inlay_hints(for_buffers)
23345        });
23346    }
23347
23348    fn inlay_hints(
23349        &self,
23350        invalidate: InvalidationStrategy,
23351        buffer: Entity<Buffer>,
23352        ranges: Vec<Range<text::Anchor>>,
23353        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23354        cx: &mut App,
23355    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23356        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23357            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23358        }))
23359    }
23360
23361    fn range_for_rename(
23362        &self,
23363        buffer: &Entity<Buffer>,
23364        position: text::Anchor,
23365        cx: &mut App,
23366    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23367        Some(self.update(cx, |project, cx| {
23368            let buffer = buffer.clone();
23369            let task = project.prepare_rename(buffer.clone(), position, cx);
23370            cx.spawn(async move |_, cx| {
23371                Ok(match task.await? {
23372                    PrepareRenameResponse::Success(range) => Some(range),
23373                    PrepareRenameResponse::InvalidPosition => None,
23374                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23375                        // Fallback on using TreeSitter info to determine identifier range
23376                        buffer.read_with(cx, |buffer, _| {
23377                            let snapshot = buffer.snapshot();
23378                            let (range, kind) = snapshot.surrounding_word(position, None);
23379                            if kind != Some(CharKind::Word) {
23380                                return None;
23381                            }
23382                            Some(
23383                                snapshot.anchor_before(range.start)
23384                                    ..snapshot.anchor_after(range.end),
23385                            )
23386                        })?
23387                    }
23388                })
23389            })
23390        }))
23391    }
23392
23393    fn perform_rename(
23394        &self,
23395        buffer: &Entity<Buffer>,
23396        position: text::Anchor,
23397        new_name: String,
23398        cx: &mut App,
23399    ) -> Option<Task<Result<ProjectTransaction>>> {
23400        Some(self.update(cx, |project, cx| {
23401            project.perform_rename(buffer.clone(), position, new_name, cx)
23402        }))
23403    }
23404}
23405
23406fn consume_contiguous_rows(
23407    contiguous_row_selections: &mut Vec<Selection<Point>>,
23408    selection: &Selection<Point>,
23409    display_map: &DisplaySnapshot,
23410    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23411) -> (MultiBufferRow, MultiBufferRow) {
23412    contiguous_row_selections.push(selection.clone());
23413    let start_row = starting_row(selection, display_map);
23414    let mut end_row = ending_row(selection, display_map);
23415
23416    while let Some(next_selection) = selections.peek() {
23417        if next_selection.start.row <= end_row.0 {
23418            end_row = ending_row(next_selection, display_map);
23419            contiguous_row_selections.push(selections.next().unwrap().clone());
23420        } else {
23421            break;
23422        }
23423    }
23424    (start_row, end_row)
23425}
23426
23427fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23428    if selection.start.column > 0 {
23429        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23430    } else {
23431        MultiBufferRow(selection.start.row)
23432    }
23433}
23434
23435fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23436    if next_selection.end.column > 0 || next_selection.is_empty() {
23437        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23438    } else {
23439        MultiBufferRow(next_selection.end.row)
23440    }
23441}
23442
23443impl EditorSnapshot {
23444    pub fn remote_selections_in_range<'a>(
23445        &'a self,
23446        range: &'a Range<Anchor>,
23447        collaboration_hub: &dyn CollaborationHub,
23448        cx: &'a App,
23449    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23450        let participant_names = collaboration_hub.user_names(cx);
23451        let participant_indices = collaboration_hub.user_participant_indices(cx);
23452        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23453        let collaborators_by_replica_id = collaborators_by_peer_id
23454            .values()
23455            .map(|collaborator| (collaborator.replica_id, collaborator))
23456            .collect::<HashMap<_, _>>();
23457        self.buffer_snapshot()
23458            .selections_in_range(range, false)
23459            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23460                if replica_id == ReplicaId::AGENT {
23461                    Some(RemoteSelection {
23462                        replica_id,
23463                        selection,
23464                        cursor_shape,
23465                        line_mode,
23466                        collaborator_id: CollaboratorId::Agent,
23467                        user_name: Some("Agent".into()),
23468                        color: cx.theme().players().agent(),
23469                    })
23470                } else {
23471                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23472                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23473                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23474                    Some(RemoteSelection {
23475                        replica_id,
23476                        selection,
23477                        cursor_shape,
23478                        line_mode,
23479                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23480                        user_name,
23481                        color: if let Some(index) = participant_index {
23482                            cx.theme().players().color_for_participant(index.0)
23483                        } else {
23484                            cx.theme().players().absent()
23485                        },
23486                    })
23487                }
23488            })
23489    }
23490
23491    pub fn hunks_for_ranges(
23492        &self,
23493        ranges: impl IntoIterator<Item = Range<Point>>,
23494    ) -> Vec<MultiBufferDiffHunk> {
23495        let mut hunks = Vec::new();
23496        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23497            HashMap::default();
23498        for query_range in ranges {
23499            let query_rows =
23500                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23501            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23502                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23503            ) {
23504                // Include deleted hunks that are adjacent to the query range, because
23505                // otherwise they would be missed.
23506                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23507                if hunk.status().is_deleted() {
23508                    intersects_range |= hunk.row_range.start == query_rows.end;
23509                    intersects_range |= hunk.row_range.end == query_rows.start;
23510                }
23511                if intersects_range {
23512                    if !processed_buffer_rows
23513                        .entry(hunk.buffer_id)
23514                        .or_default()
23515                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23516                    {
23517                        continue;
23518                    }
23519                    hunks.push(hunk);
23520                }
23521            }
23522        }
23523
23524        hunks
23525    }
23526
23527    fn display_diff_hunks_for_rows<'a>(
23528        &'a self,
23529        display_rows: Range<DisplayRow>,
23530        folded_buffers: &'a HashSet<BufferId>,
23531    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23532        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23533        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23534
23535        self.buffer_snapshot()
23536            .diff_hunks_in_range(buffer_start..buffer_end)
23537            .filter_map(|hunk| {
23538                if folded_buffers.contains(&hunk.buffer_id) {
23539                    return None;
23540                }
23541
23542                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23543                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23544
23545                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23546                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23547
23548                let display_hunk = if hunk_display_start.column() != 0 {
23549                    DisplayDiffHunk::Folded {
23550                        display_row: hunk_display_start.row(),
23551                    }
23552                } else {
23553                    let mut end_row = hunk_display_end.row();
23554                    if hunk_display_end.column() > 0 {
23555                        end_row.0 += 1;
23556                    }
23557                    let is_created_file = hunk.is_created_file();
23558                    DisplayDiffHunk::Unfolded {
23559                        status: hunk.status(),
23560                        diff_base_byte_range: hunk.diff_base_byte_range,
23561                        display_row_range: hunk_display_start.row()..end_row,
23562                        multi_buffer_range: Anchor::range_in_buffer(
23563                            hunk.excerpt_id,
23564                            hunk.buffer_id,
23565                            hunk.buffer_range,
23566                        ),
23567                        is_created_file,
23568                    }
23569                };
23570
23571                Some(display_hunk)
23572            })
23573    }
23574
23575    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23576        self.display_snapshot
23577            .buffer_snapshot()
23578            .language_at(position)
23579    }
23580
23581    pub fn is_focused(&self) -> bool {
23582        self.is_focused
23583    }
23584
23585    pub fn placeholder_text(&self) -> Option<String> {
23586        self.placeholder_display_snapshot
23587            .as_ref()
23588            .map(|display_map| display_map.text())
23589    }
23590
23591    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23592        self.scroll_anchor.scroll_position(&self.display_snapshot)
23593    }
23594
23595    fn gutter_dimensions(
23596        &self,
23597        font_id: FontId,
23598        font_size: Pixels,
23599        max_line_number_width: Pixels,
23600        cx: &App,
23601    ) -> Option<GutterDimensions> {
23602        if !self.show_gutter {
23603            return None;
23604        }
23605
23606        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23607        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23608
23609        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23610            matches!(
23611                ProjectSettings::get_global(cx).git.git_gutter,
23612                GitGutterSetting::TrackedFiles
23613            )
23614        });
23615        let gutter_settings = EditorSettings::get_global(cx).gutter;
23616        let show_line_numbers = self
23617            .show_line_numbers
23618            .unwrap_or(gutter_settings.line_numbers);
23619        let line_gutter_width = if show_line_numbers {
23620            // Avoid flicker-like gutter resizes when the line number gains another digit by
23621            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23622            let min_width_for_number_on_gutter =
23623                ch_advance * gutter_settings.min_line_number_digits as f32;
23624            max_line_number_width.max(min_width_for_number_on_gutter)
23625        } else {
23626            0.0.into()
23627        };
23628
23629        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23630        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23631
23632        let git_blame_entries_width =
23633            self.git_blame_gutter_max_author_length
23634                .map(|max_author_length| {
23635                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23636                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23637
23638                    /// The number of characters to dedicate to gaps and margins.
23639                    const SPACING_WIDTH: usize = 4;
23640
23641                    let max_char_count = max_author_length.min(renderer.max_author_length())
23642                        + ::git::SHORT_SHA_LENGTH
23643                        + MAX_RELATIVE_TIMESTAMP.len()
23644                        + SPACING_WIDTH;
23645
23646                    ch_advance * max_char_count
23647                });
23648
23649        let is_singleton = self.buffer_snapshot().is_singleton();
23650
23651        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23652        left_padding += if !is_singleton {
23653            ch_width * 4.0
23654        } else if show_runnables || show_breakpoints {
23655            ch_width * 3.0
23656        } else if show_git_gutter && show_line_numbers {
23657            ch_width * 2.0
23658        } else if show_git_gutter || show_line_numbers {
23659            ch_width
23660        } else {
23661            px(0.)
23662        };
23663
23664        let shows_folds = is_singleton && gutter_settings.folds;
23665
23666        let right_padding = if shows_folds && show_line_numbers {
23667            ch_width * 4.0
23668        } else if shows_folds || (!is_singleton && show_line_numbers) {
23669            ch_width * 3.0
23670        } else if show_line_numbers {
23671            ch_width
23672        } else {
23673            px(0.)
23674        };
23675
23676        Some(GutterDimensions {
23677            left_padding,
23678            right_padding,
23679            width: line_gutter_width + left_padding + right_padding,
23680            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23681            git_blame_entries_width,
23682        })
23683    }
23684
23685    pub fn render_crease_toggle(
23686        &self,
23687        buffer_row: MultiBufferRow,
23688        row_contains_cursor: bool,
23689        editor: Entity<Editor>,
23690        window: &mut Window,
23691        cx: &mut App,
23692    ) -> Option<AnyElement> {
23693        let folded = self.is_line_folded(buffer_row);
23694        let mut is_foldable = false;
23695
23696        if let Some(crease) = self
23697            .crease_snapshot
23698            .query_row(buffer_row, self.buffer_snapshot())
23699        {
23700            is_foldable = true;
23701            match crease {
23702                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23703                    if let Some(render_toggle) = render_toggle {
23704                        let toggle_callback =
23705                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23706                                if folded {
23707                                    editor.update(cx, |editor, cx| {
23708                                        editor.fold_at(buffer_row, window, cx)
23709                                    });
23710                                } else {
23711                                    editor.update(cx, |editor, cx| {
23712                                        editor.unfold_at(buffer_row, window, cx)
23713                                    });
23714                                }
23715                            });
23716                        return Some((render_toggle)(
23717                            buffer_row,
23718                            folded,
23719                            toggle_callback,
23720                            window,
23721                            cx,
23722                        ));
23723                    }
23724                }
23725            }
23726        }
23727
23728        is_foldable |= self.starts_indent(buffer_row);
23729
23730        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23731            Some(
23732                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23733                    .toggle_state(folded)
23734                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23735                        if folded {
23736                            this.unfold_at(buffer_row, window, cx);
23737                        } else {
23738                            this.fold_at(buffer_row, window, cx);
23739                        }
23740                    }))
23741                    .into_any_element(),
23742            )
23743        } else {
23744            None
23745        }
23746    }
23747
23748    pub fn render_crease_trailer(
23749        &self,
23750        buffer_row: MultiBufferRow,
23751        window: &mut Window,
23752        cx: &mut App,
23753    ) -> Option<AnyElement> {
23754        let folded = self.is_line_folded(buffer_row);
23755        if let Crease::Inline { render_trailer, .. } = self
23756            .crease_snapshot
23757            .query_row(buffer_row, self.buffer_snapshot())?
23758        {
23759            let render_trailer = render_trailer.as_ref()?;
23760            Some(render_trailer(buffer_row, folded, window, cx))
23761        } else {
23762            None
23763        }
23764    }
23765}
23766
23767impl Deref for EditorSnapshot {
23768    type Target = DisplaySnapshot;
23769
23770    fn deref(&self) -> &Self::Target {
23771        &self.display_snapshot
23772    }
23773}
23774
23775#[derive(Clone, Debug, PartialEq, Eq)]
23776pub enum EditorEvent {
23777    InputIgnored {
23778        text: Arc<str>,
23779    },
23780    InputHandled {
23781        utf16_range_to_replace: Option<Range<isize>>,
23782        text: Arc<str>,
23783    },
23784    ExcerptsAdded {
23785        buffer: Entity<Buffer>,
23786        predecessor: ExcerptId,
23787        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23788    },
23789    ExcerptsRemoved {
23790        ids: Vec<ExcerptId>,
23791        removed_buffer_ids: Vec<BufferId>,
23792    },
23793    BufferFoldToggled {
23794        ids: Vec<ExcerptId>,
23795        folded: bool,
23796    },
23797    ExcerptsEdited {
23798        ids: Vec<ExcerptId>,
23799    },
23800    ExcerptsExpanded {
23801        ids: Vec<ExcerptId>,
23802    },
23803    BufferEdited,
23804    Edited {
23805        transaction_id: clock::Lamport,
23806    },
23807    Reparsed(BufferId),
23808    Focused,
23809    FocusedIn,
23810    Blurred,
23811    DirtyChanged,
23812    Saved,
23813    TitleChanged,
23814    SelectionsChanged {
23815        local: bool,
23816    },
23817    ScrollPositionChanged {
23818        local: bool,
23819        autoscroll: bool,
23820    },
23821    TransactionUndone {
23822        transaction_id: clock::Lamport,
23823    },
23824    TransactionBegun {
23825        transaction_id: clock::Lamport,
23826    },
23827    CursorShapeChanged,
23828    BreadcrumbsChanged,
23829    PushedToNavHistory {
23830        anchor: Anchor,
23831        is_deactivate: bool,
23832    },
23833}
23834
23835impl EventEmitter<EditorEvent> for Editor {}
23836
23837impl Focusable for Editor {
23838    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23839        self.focus_handle.clone()
23840    }
23841}
23842
23843impl Render for Editor {
23844    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23845        let settings = ThemeSettings::get_global(cx);
23846
23847        let mut text_style = match self.mode {
23848            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23849                color: cx.theme().colors().editor_foreground,
23850                font_family: settings.ui_font.family.clone(),
23851                font_features: settings.ui_font.features.clone(),
23852                font_fallbacks: settings.ui_font.fallbacks.clone(),
23853                font_size: rems(0.875).into(),
23854                font_weight: settings.ui_font.weight,
23855                line_height: relative(settings.buffer_line_height.value()),
23856                ..Default::default()
23857            },
23858            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23859                color: cx.theme().colors().editor_foreground,
23860                font_family: settings.buffer_font.family.clone(),
23861                font_features: settings.buffer_font.features.clone(),
23862                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23863                font_size: settings.buffer_font_size(cx).into(),
23864                font_weight: settings.buffer_font.weight,
23865                line_height: relative(settings.buffer_line_height.value()),
23866                ..Default::default()
23867            },
23868        };
23869        if let Some(text_style_refinement) = &self.text_style_refinement {
23870            text_style.refine(text_style_refinement)
23871        }
23872
23873        let background = match self.mode {
23874            EditorMode::SingleLine => cx.theme().system().transparent,
23875            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23876            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23877            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23878        };
23879
23880        EditorElement::new(
23881            &cx.entity(),
23882            EditorStyle {
23883                background,
23884                border: cx.theme().colors().border,
23885                local_player: cx.theme().players().local(),
23886                text: text_style,
23887                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23888                syntax: cx.theme().syntax().clone(),
23889                status: cx.theme().status().clone(),
23890                inlay_hints_style: make_inlay_hints_style(cx),
23891                edit_prediction_styles: make_suggestion_styles(cx),
23892                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23893                show_underlines: self.diagnostics_enabled(),
23894            },
23895        )
23896    }
23897}
23898
23899impl EntityInputHandler for Editor {
23900    fn text_for_range(
23901        &mut self,
23902        range_utf16: Range<usize>,
23903        adjusted_range: &mut Option<Range<usize>>,
23904        _: &mut Window,
23905        cx: &mut Context<Self>,
23906    ) -> Option<String> {
23907        let snapshot = self.buffer.read(cx).read(cx);
23908        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23909        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23910        if (start.0..end.0) != range_utf16 {
23911            adjusted_range.replace(start.0..end.0);
23912        }
23913        Some(snapshot.text_for_range(start..end).collect())
23914    }
23915
23916    fn selected_text_range(
23917        &mut self,
23918        ignore_disabled_input: bool,
23919        _: &mut Window,
23920        cx: &mut Context<Self>,
23921    ) -> Option<UTF16Selection> {
23922        // Prevent the IME menu from appearing when holding down an alphabetic key
23923        // while input is disabled.
23924        if !ignore_disabled_input && !self.input_enabled {
23925            return None;
23926        }
23927
23928        let selection = self
23929            .selections
23930            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
23931        let range = selection.range();
23932
23933        Some(UTF16Selection {
23934            range: range.start.0..range.end.0,
23935            reversed: selection.reversed,
23936        })
23937    }
23938
23939    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23940        let snapshot = self.buffer.read(cx).read(cx);
23941        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23942        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23943    }
23944
23945    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23946        self.clear_highlights::<InputComposition>(cx);
23947        self.ime_transaction.take();
23948    }
23949
23950    fn replace_text_in_range(
23951        &mut self,
23952        range_utf16: Option<Range<usize>>,
23953        text: &str,
23954        window: &mut Window,
23955        cx: &mut Context<Self>,
23956    ) {
23957        if !self.input_enabled {
23958            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23959            return;
23960        }
23961
23962        self.transact(window, cx, |this, window, cx| {
23963            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23964                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23965                Some(this.selection_replacement_ranges(range_utf16, cx))
23966            } else {
23967                this.marked_text_ranges(cx)
23968            };
23969
23970            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23971                let newest_selection_id = this.selections.newest_anchor().id;
23972                this.selections
23973                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23974                    .iter()
23975                    .zip(ranges_to_replace.iter())
23976                    .find_map(|(selection, range)| {
23977                        if selection.id == newest_selection_id {
23978                            Some(
23979                                (range.start.0 as isize - selection.head().0 as isize)
23980                                    ..(range.end.0 as isize - selection.head().0 as isize),
23981                            )
23982                        } else {
23983                            None
23984                        }
23985                    })
23986            });
23987
23988            cx.emit(EditorEvent::InputHandled {
23989                utf16_range_to_replace: range_to_replace,
23990                text: text.into(),
23991            });
23992
23993            if let Some(new_selected_ranges) = new_selected_ranges {
23994                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23995                    selections.select_ranges(new_selected_ranges)
23996                });
23997                this.backspace(&Default::default(), window, cx);
23998            }
23999
24000            this.handle_input(text, window, cx);
24001        });
24002
24003        if let Some(transaction) = self.ime_transaction {
24004            self.buffer.update(cx, |buffer, cx| {
24005                buffer.group_until_transaction(transaction, cx);
24006            });
24007        }
24008
24009        self.unmark_text(window, cx);
24010    }
24011
24012    fn replace_and_mark_text_in_range(
24013        &mut self,
24014        range_utf16: Option<Range<usize>>,
24015        text: &str,
24016        new_selected_range_utf16: Option<Range<usize>>,
24017        window: &mut Window,
24018        cx: &mut Context<Self>,
24019    ) {
24020        if !self.input_enabled {
24021            return;
24022        }
24023
24024        let transaction = self.transact(window, cx, |this, window, cx| {
24025            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24026                let snapshot = this.buffer.read(cx).read(cx);
24027                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24028                    for marked_range in &mut marked_ranges {
24029                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24030                        marked_range.start.0 += relative_range_utf16.start;
24031                        marked_range.start =
24032                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24033                        marked_range.end =
24034                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24035                    }
24036                }
24037                Some(marked_ranges)
24038            } else if let Some(range_utf16) = range_utf16 {
24039                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24040                Some(this.selection_replacement_ranges(range_utf16, cx))
24041            } else {
24042                None
24043            };
24044
24045            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24046                let newest_selection_id = this.selections.newest_anchor().id;
24047                this.selections
24048                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24049                    .iter()
24050                    .zip(ranges_to_replace.iter())
24051                    .find_map(|(selection, range)| {
24052                        if selection.id == newest_selection_id {
24053                            Some(
24054                                (range.start.0 as isize - selection.head().0 as isize)
24055                                    ..(range.end.0 as isize - selection.head().0 as isize),
24056                            )
24057                        } else {
24058                            None
24059                        }
24060                    })
24061            });
24062
24063            cx.emit(EditorEvent::InputHandled {
24064                utf16_range_to_replace: range_to_replace,
24065                text: text.into(),
24066            });
24067
24068            if let Some(ranges) = ranges_to_replace {
24069                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24070                    s.select_ranges(ranges)
24071                });
24072            }
24073
24074            let marked_ranges = {
24075                let snapshot = this.buffer.read(cx).read(cx);
24076                this.selections
24077                    .disjoint_anchors_arc()
24078                    .iter()
24079                    .map(|selection| {
24080                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24081                    })
24082                    .collect::<Vec<_>>()
24083            };
24084
24085            if text.is_empty() {
24086                this.unmark_text(window, cx);
24087            } else {
24088                this.highlight_text::<InputComposition>(
24089                    marked_ranges.clone(),
24090                    HighlightStyle {
24091                        underline: Some(UnderlineStyle {
24092                            thickness: px(1.),
24093                            color: None,
24094                            wavy: false,
24095                        }),
24096                        ..Default::default()
24097                    },
24098                    cx,
24099                );
24100            }
24101
24102            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24103            let use_autoclose = this.use_autoclose;
24104            let use_auto_surround = this.use_auto_surround;
24105            this.set_use_autoclose(false);
24106            this.set_use_auto_surround(false);
24107            this.handle_input(text, window, cx);
24108            this.set_use_autoclose(use_autoclose);
24109            this.set_use_auto_surround(use_auto_surround);
24110
24111            if let Some(new_selected_range) = new_selected_range_utf16 {
24112                let snapshot = this.buffer.read(cx).read(cx);
24113                let new_selected_ranges = marked_ranges
24114                    .into_iter()
24115                    .map(|marked_range| {
24116                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24117                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24118                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24119                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24120                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24121                    })
24122                    .collect::<Vec<_>>();
24123
24124                drop(snapshot);
24125                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24126                    selections.select_ranges(new_selected_ranges)
24127                });
24128            }
24129        });
24130
24131        self.ime_transaction = self.ime_transaction.or(transaction);
24132        if let Some(transaction) = self.ime_transaction {
24133            self.buffer.update(cx, |buffer, cx| {
24134                buffer.group_until_transaction(transaction, cx);
24135            });
24136        }
24137
24138        if self.text_highlights::<InputComposition>(cx).is_none() {
24139            self.ime_transaction.take();
24140        }
24141    }
24142
24143    fn bounds_for_range(
24144        &mut self,
24145        range_utf16: Range<usize>,
24146        element_bounds: gpui::Bounds<Pixels>,
24147        window: &mut Window,
24148        cx: &mut Context<Self>,
24149    ) -> Option<gpui::Bounds<Pixels>> {
24150        let text_layout_details = self.text_layout_details(window);
24151        let CharacterDimensions {
24152            em_width,
24153            em_advance,
24154            line_height,
24155        } = self.character_dimensions(window);
24156
24157        let snapshot = self.snapshot(window, cx);
24158        let scroll_position = snapshot.scroll_position();
24159        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24160
24161        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24162        let x = Pixels::from(
24163            ScrollOffset::from(
24164                snapshot.x_for_display_point(start, &text_layout_details)
24165                    + self.gutter_dimensions.full_width(),
24166            ) - scroll_left,
24167        );
24168        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24169
24170        Some(Bounds {
24171            origin: element_bounds.origin + point(x, y),
24172            size: size(em_width, line_height),
24173        })
24174    }
24175
24176    fn character_index_for_point(
24177        &mut self,
24178        point: gpui::Point<Pixels>,
24179        _window: &mut Window,
24180        _cx: &mut Context<Self>,
24181    ) -> Option<usize> {
24182        let position_map = self.last_position_map.as_ref()?;
24183        if !position_map.text_hitbox.contains(&point) {
24184            return None;
24185        }
24186        let display_point = position_map.point_for_position(point).previous_valid;
24187        let anchor = position_map
24188            .snapshot
24189            .display_point_to_anchor(display_point, Bias::Left);
24190        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24191        Some(utf16_offset.0)
24192    }
24193}
24194
24195trait SelectionExt {
24196    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24197    fn spanned_rows(
24198        &self,
24199        include_end_if_at_line_start: bool,
24200        map: &DisplaySnapshot,
24201    ) -> Range<MultiBufferRow>;
24202}
24203
24204impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24205    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24206        let start = self
24207            .start
24208            .to_point(map.buffer_snapshot())
24209            .to_display_point(map);
24210        let end = self
24211            .end
24212            .to_point(map.buffer_snapshot())
24213            .to_display_point(map);
24214        if self.reversed {
24215            end..start
24216        } else {
24217            start..end
24218        }
24219    }
24220
24221    fn spanned_rows(
24222        &self,
24223        include_end_if_at_line_start: bool,
24224        map: &DisplaySnapshot,
24225    ) -> Range<MultiBufferRow> {
24226        let start = self.start.to_point(map.buffer_snapshot());
24227        let mut end = self.end.to_point(map.buffer_snapshot());
24228        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24229            end.row -= 1;
24230        }
24231
24232        let buffer_start = map.prev_line_boundary(start).0;
24233        let buffer_end = map.next_line_boundary(end).0;
24234        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24235    }
24236}
24237
24238impl<T: InvalidationRegion> InvalidationStack<T> {
24239    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24240    where
24241        S: Clone + ToOffset,
24242    {
24243        while let Some(region) = self.last() {
24244            let all_selections_inside_invalidation_ranges =
24245                if selections.len() == region.ranges().len() {
24246                    selections
24247                        .iter()
24248                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24249                        .all(|(selection, invalidation_range)| {
24250                            let head = selection.head().to_offset(buffer);
24251                            invalidation_range.start <= head && invalidation_range.end >= head
24252                        })
24253                } else {
24254                    false
24255                };
24256
24257            if all_selections_inside_invalidation_ranges {
24258                break;
24259            } else {
24260                self.pop();
24261            }
24262        }
24263    }
24264}
24265
24266impl<T> Default for InvalidationStack<T> {
24267    fn default() -> Self {
24268        Self(Default::default())
24269    }
24270}
24271
24272impl<T> Deref for InvalidationStack<T> {
24273    type Target = Vec<T>;
24274
24275    fn deref(&self) -> &Self::Target {
24276        &self.0
24277    }
24278}
24279
24280impl<T> DerefMut for InvalidationStack<T> {
24281    fn deref_mut(&mut self) -> &mut Self::Target {
24282        &mut self.0
24283    }
24284}
24285
24286impl InvalidationRegion for SnippetState {
24287    fn ranges(&self) -> &[Range<Anchor>] {
24288        &self.ranges[self.active_index]
24289    }
24290}
24291
24292fn edit_prediction_edit_text(
24293    current_snapshot: &BufferSnapshot,
24294    edits: &[(Range<Anchor>, String)],
24295    edit_preview: &EditPreview,
24296    include_deletions: bool,
24297    cx: &App,
24298) -> HighlightedText {
24299    let edits = edits
24300        .iter()
24301        .map(|(anchor, text)| {
24302            (
24303                anchor.start.text_anchor..anchor.end.text_anchor,
24304                text.clone(),
24305            )
24306        })
24307        .collect::<Vec<_>>();
24308
24309    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24310}
24311
24312fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24313    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24314    // Just show the raw edit text with basic styling
24315    let mut text = String::new();
24316    let mut highlights = Vec::new();
24317
24318    let insertion_highlight_style = HighlightStyle {
24319        color: Some(cx.theme().colors().text),
24320        ..Default::default()
24321    };
24322
24323    for (_, edit_text) in edits {
24324        let start_offset = text.len();
24325        text.push_str(edit_text);
24326        let end_offset = text.len();
24327
24328        if start_offset < end_offset {
24329            highlights.push((start_offset..end_offset, insertion_highlight_style));
24330        }
24331    }
24332
24333    HighlightedText {
24334        text: text.into(),
24335        highlights,
24336    }
24337}
24338
24339pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24340    match severity {
24341        lsp::DiagnosticSeverity::ERROR => colors.error,
24342        lsp::DiagnosticSeverity::WARNING => colors.warning,
24343        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24344        lsp::DiagnosticSeverity::HINT => colors.info,
24345        _ => colors.ignored,
24346    }
24347}
24348
24349pub fn styled_runs_for_code_label<'a>(
24350    label: &'a CodeLabel,
24351    syntax_theme: &'a theme::SyntaxTheme,
24352) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24353    let fade_out = HighlightStyle {
24354        fade_out: Some(0.35),
24355        ..Default::default()
24356    };
24357
24358    let mut prev_end = label.filter_range.end;
24359    label
24360        .runs
24361        .iter()
24362        .enumerate()
24363        .flat_map(move |(ix, (range, highlight_id))| {
24364            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24365                style
24366            } else {
24367                return Default::default();
24368            };
24369            let muted_style = style.highlight(fade_out);
24370
24371            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24372            if range.start >= label.filter_range.end {
24373                if range.start > prev_end {
24374                    runs.push((prev_end..range.start, fade_out));
24375                }
24376                runs.push((range.clone(), muted_style));
24377            } else if range.end <= label.filter_range.end {
24378                runs.push((range.clone(), style));
24379            } else {
24380                runs.push((range.start..label.filter_range.end, style));
24381                runs.push((label.filter_range.end..range.end, muted_style));
24382            }
24383            prev_end = cmp::max(prev_end, range.end);
24384
24385            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24386                runs.push((prev_end..label.text.len(), fade_out));
24387            }
24388
24389            runs
24390        })
24391}
24392
24393pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24394    let mut prev_index = 0;
24395    let mut prev_codepoint: Option<char> = None;
24396    text.char_indices()
24397        .chain([(text.len(), '\0')])
24398        .filter_map(move |(index, codepoint)| {
24399            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24400            let is_boundary = index == text.len()
24401                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24402                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24403            if is_boundary {
24404                let chunk = &text[prev_index..index];
24405                prev_index = index;
24406                Some(chunk)
24407            } else {
24408                None
24409            }
24410        })
24411}
24412
24413pub trait RangeToAnchorExt: Sized {
24414    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24415
24416    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24417        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24418        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24419    }
24420}
24421
24422impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24423    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24424        let start_offset = self.start.to_offset(snapshot);
24425        let end_offset = self.end.to_offset(snapshot);
24426        if start_offset == end_offset {
24427            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24428        } else {
24429            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24430        }
24431    }
24432}
24433
24434pub trait RowExt {
24435    fn as_f64(&self) -> f64;
24436
24437    fn next_row(&self) -> Self;
24438
24439    fn previous_row(&self) -> Self;
24440
24441    fn minus(&self, other: Self) -> u32;
24442}
24443
24444impl RowExt for DisplayRow {
24445    fn as_f64(&self) -> f64 {
24446        self.0 as _
24447    }
24448
24449    fn next_row(&self) -> Self {
24450        Self(self.0 + 1)
24451    }
24452
24453    fn previous_row(&self) -> Self {
24454        Self(self.0.saturating_sub(1))
24455    }
24456
24457    fn minus(&self, other: Self) -> u32 {
24458        self.0 - other.0
24459    }
24460}
24461
24462impl RowExt for MultiBufferRow {
24463    fn as_f64(&self) -> f64 {
24464        self.0 as _
24465    }
24466
24467    fn next_row(&self) -> Self {
24468        Self(self.0 + 1)
24469    }
24470
24471    fn previous_row(&self) -> Self {
24472        Self(self.0.saturating_sub(1))
24473    }
24474
24475    fn minus(&self, other: Self) -> u32 {
24476        self.0 - other.0
24477    }
24478}
24479
24480trait RowRangeExt {
24481    type Row;
24482
24483    fn len(&self) -> usize;
24484
24485    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24486}
24487
24488impl RowRangeExt for Range<MultiBufferRow> {
24489    type Row = MultiBufferRow;
24490
24491    fn len(&self) -> usize {
24492        (self.end.0 - self.start.0) as usize
24493    }
24494
24495    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24496        (self.start.0..self.end.0).map(MultiBufferRow)
24497    }
24498}
24499
24500impl RowRangeExt for Range<DisplayRow> {
24501    type Row = DisplayRow;
24502
24503    fn len(&self) -> usize {
24504        (self.end.0 - self.start.0) as usize
24505    }
24506
24507    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24508        (self.start.0..self.end.0).map(DisplayRow)
24509    }
24510}
24511
24512/// If select range has more than one line, we
24513/// just point the cursor to range.start.
24514fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24515    if range.start.row == range.end.row {
24516        range
24517    } else {
24518        range.start..range.start
24519    }
24520}
24521pub struct KillRing(ClipboardItem);
24522impl Global for KillRing {}
24523
24524const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24525
24526enum BreakpointPromptEditAction {
24527    Log,
24528    Condition,
24529    HitCondition,
24530}
24531
24532struct BreakpointPromptEditor {
24533    pub(crate) prompt: Entity<Editor>,
24534    editor: WeakEntity<Editor>,
24535    breakpoint_anchor: Anchor,
24536    breakpoint: Breakpoint,
24537    edit_action: BreakpointPromptEditAction,
24538    block_ids: HashSet<CustomBlockId>,
24539    editor_margins: Arc<Mutex<EditorMargins>>,
24540    _subscriptions: Vec<Subscription>,
24541}
24542
24543impl BreakpointPromptEditor {
24544    const MAX_LINES: u8 = 4;
24545
24546    fn new(
24547        editor: WeakEntity<Editor>,
24548        breakpoint_anchor: Anchor,
24549        breakpoint: Breakpoint,
24550        edit_action: BreakpointPromptEditAction,
24551        window: &mut Window,
24552        cx: &mut Context<Self>,
24553    ) -> Self {
24554        let base_text = match edit_action {
24555            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24556            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24557            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24558        }
24559        .map(|msg| msg.to_string())
24560        .unwrap_or_default();
24561
24562        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24563        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24564
24565        let prompt = cx.new(|cx| {
24566            let mut prompt = Editor::new(
24567                EditorMode::AutoHeight {
24568                    min_lines: 1,
24569                    max_lines: Some(Self::MAX_LINES as usize),
24570                },
24571                buffer,
24572                None,
24573                window,
24574                cx,
24575            );
24576            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24577            prompt.set_show_cursor_when_unfocused(false, cx);
24578            prompt.set_placeholder_text(
24579                match edit_action {
24580                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24581                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24582                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24583                },
24584                window,
24585                cx,
24586            );
24587
24588            prompt
24589        });
24590
24591        Self {
24592            prompt,
24593            editor,
24594            breakpoint_anchor,
24595            breakpoint,
24596            edit_action,
24597            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24598            block_ids: Default::default(),
24599            _subscriptions: vec![],
24600        }
24601    }
24602
24603    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24604        self.block_ids.extend(block_ids)
24605    }
24606
24607    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24608        if let Some(editor) = self.editor.upgrade() {
24609            let message = self
24610                .prompt
24611                .read(cx)
24612                .buffer
24613                .read(cx)
24614                .as_singleton()
24615                .expect("A multi buffer in breakpoint prompt isn't possible")
24616                .read(cx)
24617                .as_rope()
24618                .to_string();
24619
24620            editor.update(cx, |editor, cx| {
24621                editor.edit_breakpoint_at_anchor(
24622                    self.breakpoint_anchor,
24623                    self.breakpoint.clone(),
24624                    match self.edit_action {
24625                        BreakpointPromptEditAction::Log => {
24626                            BreakpointEditAction::EditLogMessage(message.into())
24627                        }
24628                        BreakpointPromptEditAction::Condition => {
24629                            BreakpointEditAction::EditCondition(message.into())
24630                        }
24631                        BreakpointPromptEditAction::HitCondition => {
24632                            BreakpointEditAction::EditHitCondition(message.into())
24633                        }
24634                    },
24635                    cx,
24636                );
24637
24638                editor.remove_blocks(self.block_ids.clone(), None, cx);
24639                cx.focus_self(window);
24640            });
24641        }
24642    }
24643
24644    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24645        self.editor
24646            .update(cx, |editor, cx| {
24647                editor.remove_blocks(self.block_ids.clone(), None, cx);
24648                window.focus(&editor.focus_handle);
24649            })
24650            .log_err();
24651    }
24652
24653    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24654        let settings = ThemeSettings::get_global(cx);
24655        let text_style = TextStyle {
24656            color: if self.prompt.read(cx).read_only(cx) {
24657                cx.theme().colors().text_disabled
24658            } else {
24659                cx.theme().colors().text
24660            },
24661            font_family: settings.buffer_font.family.clone(),
24662            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24663            font_size: settings.buffer_font_size(cx).into(),
24664            font_weight: settings.buffer_font.weight,
24665            line_height: relative(settings.buffer_line_height.value()),
24666            ..Default::default()
24667        };
24668        EditorElement::new(
24669            &self.prompt,
24670            EditorStyle {
24671                background: cx.theme().colors().editor_background,
24672                local_player: cx.theme().players().local(),
24673                text: text_style,
24674                ..Default::default()
24675            },
24676        )
24677    }
24678}
24679
24680impl Render for BreakpointPromptEditor {
24681    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24682        let editor_margins = *self.editor_margins.lock();
24683        let gutter_dimensions = editor_margins.gutter;
24684        h_flex()
24685            .key_context("Editor")
24686            .bg(cx.theme().colors().editor_background)
24687            .border_y_1()
24688            .border_color(cx.theme().status().info_border)
24689            .size_full()
24690            .py(window.line_height() / 2.5)
24691            .on_action(cx.listener(Self::confirm))
24692            .on_action(cx.listener(Self::cancel))
24693            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24694            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24695    }
24696}
24697
24698impl Focusable for BreakpointPromptEditor {
24699    fn focus_handle(&self, cx: &App) -> FocusHandle {
24700        self.prompt.focus_handle(cx)
24701    }
24702}
24703
24704fn all_edits_insertions_or_deletions(
24705    edits: &Vec<(Range<Anchor>, String)>,
24706    snapshot: &MultiBufferSnapshot,
24707) -> bool {
24708    let mut all_insertions = true;
24709    let mut all_deletions = true;
24710
24711    for (range, new_text) in edits.iter() {
24712        let range_is_empty = range.to_offset(snapshot).is_empty();
24713        let text_is_empty = new_text.is_empty();
24714
24715        if range_is_empty != text_is_empty {
24716            if range_is_empty {
24717                all_deletions = false;
24718            } else {
24719                all_insertions = false;
24720            }
24721        } else {
24722            return false;
24723        }
24724
24725        if !all_insertions && !all_deletions {
24726            return false;
24727        }
24728    }
24729    all_insertions || all_deletions
24730}
24731
24732struct MissingEditPredictionKeybindingTooltip;
24733
24734impl Render for MissingEditPredictionKeybindingTooltip {
24735    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24736        ui::tooltip_container(cx, |container, cx| {
24737            container
24738                .flex_shrink_0()
24739                .max_w_80()
24740                .min_h(rems_from_px(124.))
24741                .justify_between()
24742                .child(
24743                    v_flex()
24744                        .flex_1()
24745                        .text_ui_sm(cx)
24746                        .child(Label::new("Conflict with Accept Keybinding"))
24747                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24748                )
24749                .child(
24750                    h_flex()
24751                        .pb_1()
24752                        .gap_1()
24753                        .items_end()
24754                        .w_full()
24755                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24756                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24757                        }))
24758                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24759                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24760                        })),
24761                )
24762        })
24763    }
24764}
24765
24766#[derive(Debug, Clone, Copy, PartialEq)]
24767pub struct LineHighlight {
24768    pub background: Background,
24769    pub border: Option<gpui::Hsla>,
24770    pub include_gutter: bool,
24771    pub type_id: Option<TypeId>,
24772}
24773
24774struct LineManipulationResult {
24775    pub new_text: String,
24776    pub line_count_before: usize,
24777    pub line_count_after: usize,
24778}
24779
24780fn render_diff_hunk_controls(
24781    row: u32,
24782    status: &DiffHunkStatus,
24783    hunk_range: Range<Anchor>,
24784    is_created_file: bool,
24785    line_height: Pixels,
24786    editor: &Entity<Editor>,
24787    _window: &mut Window,
24788    cx: &mut App,
24789) -> AnyElement {
24790    h_flex()
24791        .h(line_height)
24792        .mr_1()
24793        .gap_1()
24794        .px_0p5()
24795        .pb_1()
24796        .border_x_1()
24797        .border_b_1()
24798        .border_color(cx.theme().colors().border_variant)
24799        .rounded_b_lg()
24800        .bg(cx.theme().colors().editor_background)
24801        .gap_1()
24802        .block_mouse_except_scroll()
24803        .shadow_md()
24804        .child(if status.has_secondary_hunk() {
24805            Button::new(("stage", row as u64), "Stage")
24806                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24807                .tooltip({
24808                    let focus_handle = editor.focus_handle(cx);
24809                    move |_window, cx| {
24810                        Tooltip::for_action_in(
24811                            "Stage Hunk",
24812                            &::git::ToggleStaged,
24813                            &focus_handle,
24814                            cx,
24815                        )
24816                    }
24817                })
24818                .on_click({
24819                    let editor = editor.clone();
24820                    move |_event, _window, cx| {
24821                        editor.update(cx, |editor, cx| {
24822                            editor.stage_or_unstage_diff_hunks(
24823                                true,
24824                                vec![hunk_range.start..hunk_range.start],
24825                                cx,
24826                            );
24827                        });
24828                    }
24829                })
24830        } else {
24831            Button::new(("unstage", row as u64), "Unstage")
24832                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24833                .tooltip({
24834                    let focus_handle = editor.focus_handle(cx);
24835                    move |_window, cx| {
24836                        Tooltip::for_action_in(
24837                            "Unstage Hunk",
24838                            &::git::ToggleStaged,
24839                            &focus_handle,
24840                            cx,
24841                        )
24842                    }
24843                })
24844                .on_click({
24845                    let editor = editor.clone();
24846                    move |_event, _window, cx| {
24847                        editor.update(cx, |editor, cx| {
24848                            editor.stage_or_unstage_diff_hunks(
24849                                false,
24850                                vec![hunk_range.start..hunk_range.start],
24851                                cx,
24852                            );
24853                        });
24854                    }
24855                })
24856        })
24857        .child(
24858            Button::new(("restore", row as u64), "Restore")
24859                .tooltip({
24860                    let focus_handle = editor.focus_handle(cx);
24861                    move |_window, cx| {
24862                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
24863                    }
24864                })
24865                .on_click({
24866                    let editor = editor.clone();
24867                    move |_event, window, cx| {
24868                        editor.update(cx, |editor, cx| {
24869                            let snapshot = editor.snapshot(window, cx);
24870                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24871                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24872                        });
24873                    }
24874                })
24875                .disabled(is_created_file),
24876        )
24877        .when(
24878            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24879            |el| {
24880                el.child(
24881                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24882                        .shape(IconButtonShape::Square)
24883                        .icon_size(IconSize::Small)
24884                        // .disabled(!has_multiple_hunks)
24885                        .tooltip({
24886                            let focus_handle = editor.focus_handle(cx);
24887                            move |_window, cx| {
24888                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
24889                            }
24890                        })
24891                        .on_click({
24892                            let editor = editor.clone();
24893                            move |_event, window, cx| {
24894                                editor.update(cx, |editor, cx| {
24895                                    let snapshot = editor.snapshot(window, cx);
24896                                    let position =
24897                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24898                                    editor.go_to_hunk_before_or_after_position(
24899                                        &snapshot,
24900                                        position,
24901                                        Direction::Next,
24902                                        window,
24903                                        cx,
24904                                    );
24905                                    editor.expand_selected_diff_hunks(cx);
24906                                });
24907                            }
24908                        }),
24909                )
24910                .child(
24911                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24912                        .shape(IconButtonShape::Square)
24913                        .icon_size(IconSize::Small)
24914                        // .disabled(!has_multiple_hunks)
24915                        .tooltip({
24916                            let focus_handle = editor.focus_handle(cx);
24917                            move |_window, cx| {
24918                                Tooltip::for_action_in(
24919                                    "Previous Hunk",
24920                                    &GoToPreviousHunk,
24921                                    &focus_handle,
24922                                    cx,
24923                                )
24924                            }
24925                        })
24926                        .on_click({
24927                            let editor = editor.clone();
24928                            move |_event, window, cx| {
24929                                editor.update(cx, |editor, cx| {
24930                                    let snapshot = editor.snapshot(window, cx);
24931                                    let point =
24932                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24933                                    editor.go_to_hunk_before_or_after_position(
24934                                        &snapshot,
24935                                        point,
24936                                        Direction::Prev,
24937                                        window,
24938                                        cx,
24939                                    );
24940                                    editor.expand_selected_diff_hunks(cx);
24941                                });
24942                            }
24943                        }),
24944                )
24945            },
24946        )
24947        .into_any_element()
24948}
24949
24950pub fn multibuffer_context_lines(cx: &App) -> u32 {
24951    EditorSettings::try_get(cx)
24952        .map(|settings| settings.excerpt_context_lines)
24953        .unwrap_or(2)
24954        .min(32)
24955}