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 bracket_colorization;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlays;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod rust_analyzer_ext;
   37pub mod scroll;
   38mod selections_collection;
   39pub mod tasks;
   40
   41#[cfg(test)]
   42mod code_completion_tests;
   43#[cfg(test)]
   44mod edit_prediction_tests;
   45#[cfg(test)]
   46mod editor_tests;
   47mod signature_help;
   48#[cfg(any(test, feature = "test-support"))]
   49pub mod test;
   50
   51pub(crate) use actions::*;
   52pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   53pub use edit_prediction::Direction;
   54pub use editor_settings::{
   55    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   56    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   57};
   58pub use element::{
   59    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   60};
   61pub use git::blame::BlameRenderer;
   62pub use hover_popover::hover_markdown_style;
   63pub use inlays::Inlay;
   64pub use items::MAX_TAB_TITLE_LEN;
   65pub use lsp::CompletionContext;
   66pub use lsp_ext::lsp_tasks;
   67pub use multi_buffer::{
   68    Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   69    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   70    ToPoint,
   71};
   72pub use text::Bias;
   73
   74use ::git::{
   75    Restore,
   76    blame::{BlameEntry, ParsedCommitMessage},
   77    status::FileStatus,
   78};
   79use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   80use anyhow::{Context as _, Result, anyhow};
   81use blink_manager::BlinkManager;
   82use buffer_diff::DiffHunkStatus;
   83use client::{Collaborator, ParticipantIndex, parse_zed_link};
   84use clock::ReplicaId;
   85use code_context_menus::{
   86    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   87    CompletionsMenu, ContextMenuOrigin,
   88};
   89use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   90use convert_case::{Case, Casing};
   91use dap::TelemetrySpawnLocation;
   92use display_map::*;
   93use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   94use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   95use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   96use futures::{
   97    FutureExt, StreamExt as _,
   98    future::{self, Shared, join},
   99    stream::FuturesUnordered,
  100};
  101use fuzzy::{StringMatch, StringMatchCandidate};
  102use git::blame::{GitBlame, GlobalBlameRenderer};
  103use gpui::{
  104    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  105    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  106    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  107    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  108    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  109    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  110    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  111    div, point, prelude::*, pulsating_between, px, relative, size,
  112};
  113use hover_links::{HoverLink, HoveredLinkState, find_file};
  114use hover_popover::{HoverState, hide_hover};
  115use indent_guides::ActiveIndentGuidesState;
  116use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  117use itertools::{Either, Itertools};
  118use language::{
  119    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  120    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  121    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  122    IndentSize, Language, LanguageName, LanguageRegistry, OffsetRangeExt, OutlineItem, Point,
  123    Runnable, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  124    language_settings::{
  125        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  126        all_language_settings, language_settings,
  127    },
  128    point_from_lsp, point_to_lsp, text_diff_with_options,
  129};
  130use linked_editing_ranges::refresh_linked_ranges;
  131use lsp::{
  132    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  133    LanguageServerId,
  134};
  135use lsp_colors::LspColorData;
  136use markdown::Markdown;
  137use mouse_context_menu::MouseContextMenu;
  138use movement::TextLayoutDetails;
  139use multi_buffer::{
  140    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  141};
  142use parking_lot::Mutex;
  143use persistence::DB;
  144use project::{
  145    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  146    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  147    InvalidationStrategy, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem,
  148    ProjectPath, ProjectTransaction, TaskSourceKind,
  149    debugger::{
  150        breakpoint_store::{
  151            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  152            BreakpointStore, BreakpointStoreEvent,
  153        },
  154        session::{Session, SessionEvent},
  155    },
  156    git_store::GitStoreEvent,
  157    lsp_store::{
  158        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  159        OpenLspBufferHandle,
  160    },
  161    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  162};
  163use rand::seq::SliceRandom;
  164use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  165use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  166use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  167use serde::{Deserialize, Serialize};
  168use settings::{
  169    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  170    update_settings_file,
  171};
  172use smallvec::{SmallVec, smallvec};
  173use snippet::Snippet;
  174use std::{
  175    any::{Any, TypeId},
  176    borrow::Cow,
  177    cell::{OnceCell, RefCell},
  178    cmp::{self, Ordering, Reverse},
  179    collections::hash_map,
  180    iter::{self, Peekable},
  181    mem,
  182    num::NonZeroU32,
  183    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  184    path::{Path, PathBuf},
  185    rc::Rc,
  186    sync::Arc,
  187    time::{Duration, Instant},
  188};
  189use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  190use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  191use theme::{
  192    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  193    observe_buffer_font_size_adjustment,
  194};
  195use ui::{
  196    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  197    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  198};
  199use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  200use workspace::{
  201    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  202    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  203    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  204    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  205    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  206    searchable::SearchEvent,
  207};
  208
  209use crate::{
  210    code_context_menus::CompletionsMenuSource,
  211    editor_settings::MultiCursorModifier,
  212    hover_links::{find_url, find_url_from_range},
  213    inlays::{
  214        InlineValueCache,
  215        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  216    },
  217    scroll::{ScrollOffset, ScrollPixelOffset},
  218    selections_collection::resolve_selections_wrapping_blocks,
  219    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  220};
  221
  222pub const FILE_HEADER_HEIGHT: u32 = 2;
  223pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  224const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  225const MAX_LINE_LEN: usize = 1024;
  226const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  227const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  228pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  229#[doc(hidden)]
  230pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  231pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  232
  233pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  234pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  235pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  236pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  237
  238pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  239pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  240pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  241
  242pub type RenderDiffHunkControlsFn = Arc<
  243    dyn Fn(
  244        u32,
  245        &DiffHunkStatus,
  246        Range<Anchor>,
  247        bool,
  248        Pixels,
  249        &Entity<Editor>,
  250        &mut Window,
  251        &mut App,
  252    ) -> AnyElement,
  253>;
  254
  255enum ReportEditorEvent {
  256    Saved { auto_saved: bool },
  257    EditorOpened,
  258    Closed,
  259}
  260
  261impl ReportEditorEvent {
  262    pub fn event_type(&self) -> &'static str {
  263        match self {
  264            Self::Saved { .. } => "Editor Saved",
  265            Self::EditorOpened => "Editor Opened",
  266            Self::Closed => "Editor Closed",
  267        }
  268    }
  269}
  270
  271pub enum ActiveDebugLine {}
  272pub enum DebugStackFrameLine {}
  273enum DocumentHighlightRead {}
  274enum DocumentHighlightWrite {}
  275enum InputComposition {}
  276pub enum PendingInput {}
  277enum SelectedTextHighlight {}
  278
  279pub enum ConflictsOuter {}
  280pub enum ConflictsOurs {}
  281pub enum ConflictsTheirs {}
  282pub enum ConflictsOursMarker {}
  283pub enum ConflictsTheirsMarker {}
  284
  285#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  286pub enum Navigated {
  287    Yes,
  288    No,
  289}
  290
  291impl Navigated {
  292    pub fn from_bool(yes: bool) -> Navigated {
  293        if yes { Navigated::Yes } else { Navigated::No }
  294    }
  295}
  296
  297#[derive(Debug, Clone, PartialEq, Eq)]
  298enum DisplayDiffHunk {
  299    Folded {
  300        display_row: DisplayRow,
  301    },
  302    Unfolded {
  303        is_created_file: bool,
  304        diff_base_byte_range: Range<usize>,
  305        display_row_range: Range<DisplayRow>,
  306        multi_buffer_range: Range<Anchor>,
  307        status: DiffHunkStatus,
  308    },
  309}
  310
  311pub enum HideMouseCursorOrigin {
  312    TypingAction,
  313    MovementAction,
  314}
  315
  316pub fn init(cx: &mut App) {
  317    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  318
  319    workspace::register_project_item::<Editor>(cx);
  320    workspace::FollowableViewRegistry::register::<Editor>(cx);
  321    workspace::register_serializable_item::<Editor>(cx);
  322
  323    cx.observe_new(
  324        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  325            workspace.register_action(Editor::new_file);
  326            workspace.register_action(Editor::new_file_split);
  327            workspace.register_action(Editor::new_file_vertical);
  328            workspace.register_action(Editor::new_file_horizontal);
  329            workspace.register_action(Editor::cancel_language_server_work);
  330            workspace.register_action(Editor::toggle_focus);
  331        },
  332    )
  333    .detach();
  334
  335    cx.on_action(move |_: &workspace::NewFile, cx| {
  336        let app_state = workspace::AppState::global(cx);
  337        if let Some(app_state) = app_state.upgrade() {
  338            workspace::open_new(
  339                Default::default(),
  340                app_state,
  341                cx,
  342                |workspace, window, cx| {
  343                    Editor::new_file(workspace, &Default::default(), window, cx)
  344                },
  345            )
  346            .detach();
  347        }
  348    });
  349    cx.on_action(move |_: &workspace::NewWindow, cx| {
  350        let app_state = workspace::AppState::global(cx);
  351        if let Some(app_state) = app_state.upgrade() {
  352            workspace::open_new(
  353                Default::default(),
  354                app_state,
  355                cx,
  356                |workspace, window, cx| {
  357                    cx.activate(true);
  358                    Editor::new_file(workspace, &Default::default(), window, cx)
  359                },
  360            )
  361            .detach();
  362        }
  363    });
  364}
  365
  366pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  367    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  368}
  369
  370pub trait DiagnosticRenderer {
  371    fn render_group(
  372        &self,
  373        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  374        buffer_id: BufferId,
  375        snapshot: EditorSnapshot,
  376        editor: WeakEntity<Editor>,
  377        language_registry: Option<Arc<LanguageRegistry>>,
  378        cx: &mut App,
  379    ) -> Vec<BlockProperties<Anchor>>;
  380
  381    fn render_hover(
  382        &self,
  383        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  384        range: Range<Point>,
  385        buffer_id: BufferId,
  386        language_registry: Option<Arc<LanguageRegistry>>,
  387        cx: &mut App,
  388    ) -> Option<Entity<markdown::Markdown>>;
  389
  390    fn open_link(
  391        &self,
  392        editor: &mut Editor,
  393        link: SharedString,
  394        window: &mut Window,
  395        cx: &mut Context<Editor>,
  396    );
  397}
  398
  399pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  400
  401impl GlobalDiagnosticRenderer {
  402    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  403        cx.try_global::<Self>().map(|g| g.0.clone())
  404    }
  405}
  406
  407impl gpui::Global for GlobalDiagnosticRenderer {}
  408pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  409    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  410}
  411
  412pub struct SearchWithinRange;
  413
  414trait InvalidationRegion {
  415    fn ranges(&self) -> &[Range<Anchor>];
  416}
  417
  418#[derive(Clone, Debug, PartialEq)]
  419pub enum SelectPhase {
  420    Begin {
  421        position: DisplayPoint,
  422        add: bool,
  423        click_count: usize,
  424    },
  425    BeginColumnar {
  426        position: DisplayPoint,
  427        reset: bool,
  428        mode: ColumnarMode,
  429        goal_column: u32,
  430    },
  431    Extend {
  432        position: DisplayPoint,
  433        click_count: usize,
  434    },
  435    Update {
  436        position: DisplayPoint,
  437        goal_column: u32,
  438        scroll_delta: gpui::Point<f32>,
  439    },
  440    End,
  441}
  442
  443#[derive(Clone, Debug, PartialEq)]
  444pub enum ColumnarMode {
  445    FromMouse,
  446    FromSelection,
  447}
  448
  449#[derive(Clone, Debug)]
  450pub enum SelectMode {
  451    Character,
  452    Word(Range<Anchor>),
  453    Line(Range<Anchor>),
  454    All,
  455}
  456
  457#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  458pub enum SizingBehavior {
  459    /// The editor will layout itself using `size_full` and will include the vertical
  460    /// scroll margin as requested by user settings.
  461    #[default]
  462    Default,
  463    /// The editor will layout itself using `size_full`, but will not have any
  464    /// vertical overscroll.
  465    ExcludeOverscrollMargin,
  466    /// The editor will request a vertical size according to its content and will be
  467    /// layouted without a vertical scroll margin.
  468    SizeByContent,
  469}
  470
  471#[derive(Clone, PartialEq, Eq, Debug)]
  472pub enum EditorMode {
  473    SingleLine,
  474    AutoHeight {
  475        min_lines: usize,
  476        max_lines: Option<usize>,
  477    },
  478    Full {
  479        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  480        scale_ui_elements_with_buffer_font_size: bool,
  481        /// When set to `true`, the editor will render a background for the active line.
  482        show_active_line_background: bool,
  483        /// Determines the sizing behavior for this editor
  484        sizing_behavior: SizingBehavior,
  485    },
  486    Minimap {
  487        parent: WeakEntity<Editor>,
  488    },
  489}
  490
  491impl EditorMode {
  492    pub fn full() -> Self {
  493        Self::Full {
  494            scale_ui_elements_with_buffer_font_size: true,
  495            show_active_line_background: true,
  496            sizing_behavior: SizingBehavior::Default,
  497        }
  498    }
  499
  500    #[inline]
  501    pub fn is_full(&self) -> bool {
  502        matches!(self, Self::Full { .. })
  503    }
  504
  505    #[inline]
  506    pub fn is_single_line(&self) -> bool {
  507        matches!(self, Self::SingleLine { .. })
  508    }
  509
  510    #[inline]
  511    fn is_minimap(&self) -> bool {
  512        matches!(self, Self::Minimap { .. })
  513    }
  514}
  515
  516#[derive(Copy, Clone, Debug)]
  517pub enum SoftWrap {
  518    /// Prefer not to wrap at all.
  519    ///
  520    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  521    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  522    GitDiff,
  523    /// Prefer a single line generally, unless an overly long line is encountered.
  524    None,
  525    /// Soft wrap lines that exceed the editor width.
  526    EditorWidth,
  527    /// Soft wrap lines at the preferred line length.
  528    Column(u32),
  529    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  530    Bounded(u32),
  531}
  532
  533#[derive(Clone)]
  534pub struct EditorStyle {
  535    pub background: Hsla,
  536    pub border: Hsla,
  537    pub local_player: PlayerColor,
  538    pub text: TextStyle,
  539    pub scrollbar_width: Pixels,
  540    pub syntax: Arc<SyntaxTheme>,
  541    pub status: StatusColors,
  542    pub inlay_hints_style: HighlightStyle,
  543    pub edit_prediction_styles: EditPredictionStyles,
  544    pub unnecessary_code_fade: f32,
  545    pub show_underlines: bool,
  546}
  547
  548impl Default for EditorStyle {
  549    fn default() -> Self {
  550        Self {
  551            background: Hsla::default(),
  552            border: Hsla::default(),
  553            local_player: PlayerColor::default(),
  554            text: TextStyle::default(),
  555            scrollbar_width: Pixels::default(),
  556            syntax: Default::default(),
  557            // HACK: Status colors don't have a real default.
  558            // We should look into removing the status colors from the editor
  559            // style and retrieve them directly from the theme.
  560            status: StatusColors::dark(),
  561            inlay_hints_style: HighlightStyle::default(),
  562            edit_prediction_styles: EditPredictionStyles {
  563                insertion: HighlightStyle::default(),
  564                whitespace: HighlightStyle::default(),
  565            },
  566            unnecessary_code_fade: Default::default(),
  567            show_underlines: true,
  568        }
  569    }
  570}
  571
  572pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  573    let show_background = language_settings::language_settings(None, None, cx)
  574        .inlay_hints
  575        .show_background;
  576
  577    let mut style = cx.theme().syntax().get("hint");
  578
  579    if style.color.is_none() {
  580        style.color = Some(cx.theme().status().hint);
  581    }
  582
  583    if !show_background {
  584        style.background_color = None;
  585        return style;
  586    }
  587
  588    if style.background_color.is_none() {
  589        style.background_color = Some(cx.theme().status().hint_background);
  590    }
  591
  592    style
  593}
  594
  595pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  596    EditPredictionStyles {
  597        insertion: HighlightStyle {
  598            color: Some(cx.theme().status().predictive),
  599            ..HighlightStyle::default()
  600        },
  601        whitespace: HighlightStyle {
  602            background_color: Some(cx.theme().status().created_background),
  603            ..HighlightStyle::default()
  604        },
  605    }
  606}
  607
  608type CompletionId = usize;
  609
  610pub(crate) enum EditDisplayMode {
  611    TabAccept,
  612    DiffPopover,
  613    Inline,
  614}
  615
  616enum EditPrediction {
  617    Edit {
  618        edits: Vec<(Range<Anchor>, Arc<str>)>,
  619        edit_preview: Option<EditPreview>,
  620        display_mode: EditDisplayMode,
  621        snapshot: BufferSnapshot,
  622    },
  623    /// Move to a specific location in the active editor
  624    MoveWithin {
  625        target: Anchor,
  626        snapshot: BufferSnapshot,
  627    },
  628    /// Move to a specific location in a different editor (not the active one)
  629    MoveOutside {
  630        target: language::Anchor,
  631        snapshot: BufferSnapshot,
  632    },
  633}
  634
  635struct EditPredictionState {
  636    inlay_ids: Vec<InlayId>,
  637    completion: EditPrediction,
  638    completion_id: Option<SharedString>,
  639    invalidation_range: Option<Range<Anchor>>,
  640}
  641
  642enum EditPredictionSettings {
  643    Disabled,
  644    Enabled {
  645        show_in_menu: bool,
  646        preview_requires_modifier: bool,
  647    },
  648}
  649
  650enum EditPredictionHighlight {}
  651
  652#[derive(Debug, Clone)]
  653struct InlineDiagnostic {
  654    message: SharedString,
  655    group_id: usize,
  656    is_primary: bool,
  657    start: Point,
  658    severity: lsp::DiagnosticSeverity,
  659}
  660
  661pub enum MenuEditPredictionsPolicy {
  662    Never,
  663    ByProvider,
  664}
  665
  666pub enum EditPredictionPreview {
  667    /// Modifier is not pressed
  668    Inactive { released_too_fast: bool },
  669    /// Modifier pressed
  670    Active {
  671        since: Instant,
  672        previous_scroll_position: Option<ScrollAnchor>,
  673    },
  674}
  675
  676impl EditPredictionPreview {
  677    pub fn released_too_fast(&self) -> bool {
  678        match self {
  679            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  680            EditPredictionPreview::Active { .. } => false,
  681        }
  682    }
  683
  684    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  685        if let EditPredictionPreview::Active {
  686            previous_scroll_position,
  687            ..
  688        } = self
  689        {
  690            *previous_scroll_position = scroll_position;
  691        }
  692    }
  693}
  694
  695pub struct ContextMenuOptions {
  696    pub min_entries_visible: usize,
  697    pub max_entries_visible: usize,
  698    pub placement: Option<ContextMenuPlacement>,
  699}
  700
  701#[derive(Debug, Clone, PartialEq, Eq)]
  702pub enum ContextMenuPlacement {
  703    Above,
  704    Below,
  705}
  706
  707#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  708struct EditorActionId(usize);
  709
  710impl EditorActionId {
  711    pub fn post_inc(&mut self) -> Self {
  712        let answer = self.0;
  713
  714        *self = Self(answer + 1);
  715
  716        Self(answer)
  717    }
  718}
  719
  720// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  721// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  722
  723type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  724type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  725
  726#[derive(Default)]
  727struct ScrollbarMarkerState {
  728    scrollbar_size: Size<Pixels>,
  729    dirty: bool,
  730    markers: Arc<[PaintQuad]>,
  731    pending_refresh: Option<Task<Result<()>>>,
  732}
  733
  734impl ScrollbarMarkerState {
  735    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  736        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  737    }
  738}
  739
  740#[derive(Clone, Copy, PartialEq, Eq)]
  741pub enum MinimapVisibility {
  742    Disabled,
  743    Enabled {
  744        /// The configuration currently present in the users settings.
  745        setting_configuration: bool,
  746        /// Whether to override the currently set visibility from the users setting.
  747        toggle_override: bool,
  748    },
  749}
  750
  751impl MinimapVisibility {
  752    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  753        if mode.is_full() {
  754            Self::Enabled {
  755                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  756                toggle_override: false,
  757            }
  758        } else {
  759            Self::Disabled
  760        }
  761    }
  762
  763    fn hidden(&self) -> Self {
  764        match *self {
  765            Self::Enabled {
  766                setting_configuration,
  767                ..
  768            } => Self::Enabled {
  769                setting_configuration,
  770                toggle_override: setting_configuration,
  771            },
  772            Self::Disabled => Self::Disabled,
  773        }
  774    }
  775
  776    fn disabled(&self) -> bool {
  777        matches!(*self, Self::Disabled)
  778    }
  779
  780    fn settings_visibility(&self) -> bool {
  781        match *self {
  782            Self::Enabled {
  783                setting_configuration,
  784                ..
  785            } => setting_configuration,
  786            _ => false,
  787        }
  788    }
  789
  790    fn visible(&self) -> bool {
  791        match *self {
  792            Self::Enabled {
  793                setting_configuration,
  794                toggle_override,
  795            } => setting_configuration ^ toggle_override,
  796            _ => false,
  797        }
  798    }
  799
  800    fn toggle_visibility(&self) -> Self {
  801        match *self {
  802            Self::Enabled {
  803                toggle_override,
  804                setting_configuration,
  805            } => Self::Enabled {
  806                setting_configuration,
  807                toggle_override: !toggle_override,
  808            },
  809            Self::Disabled => Self::Disabled,
  810        }
  811    }
  812}
  813
  814#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  815pub enum BufferSerialization {
  816    All,
  817    NonDirtyBuffers,
  818}
  819
  820impl BufferSerialization {
  821    fn new(restore_unsaved_buffers: bool) -> Self {
  822        if restore_unsaved_buffers {
  823            Self::All
  824        } else {
  825            Self::NonDirtyBuffers
  826        }
  827    }
  828}
  829
  830#[derive(Clone, Debug)]
  831struct RunnableTasks {
  832    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  833    offset: multi_buffer::Anchor,
  834    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  835    column: u32,
  836    // Values of all named captures, including those starting with '_'
  837    extra_variables: HashMap<String, String>,
  838    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  839    context_range: Range<BufferOffset>,
  840}
  841
  842impl RunnableTasks {
  843    fn resolve<'a>(
  844        &'a self,
  845        cx: &'a task::TaskContext,
  846    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  847        self.templates.iter().filter_map(|(kind, template)| {
  848            template
  849                .resolve_task(&kind.to_id_base(), cx)
  850                .map(|task| (kind.clone(), task))
  851        })
  852    }
  853}
  854
  855#[derive(Clone)]
  856pub struct ResolvedTasks {
  857    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  858    position: Anchor,
  859}
  860
  861/// Addons allow storing per-editor state in other crates (e.g. Vim)
  862pub trait Addon: 'static {
  863    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  864
  865    fn render_buffer_header_controls(
  866        &self,
  867        _: &ExcerptInfo,
  868        _: &Window,
  869        _: &App,
  870    ) -> Option<AnyElement> {
  871        None
  872    }
  873
  874    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  875        None
  876    }
  877
  878    fn to_any(&self) -> &dyn std::any::Any;
  879
  880    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  881        None
  882    }
  883}
  884
  885struct ChangeLocation {
  886    current: Option<Vec<Anchor>>,
  887    original: Vec<Anchor>,
  888}
  889impl ChangeLocation {
  890    fn locations(&self) -> &[Anchor] {
  891        self.current.as_ref().unwrap_or(&self.original)
  892    }
  893}
  894
  895/// A set of caret positions, registered when the editor was edited.
  896pub struct ChangeList {
  897    changes: Vec<ChangeLocation>,
  898    /// Currently "selected" change.
  899    position: Option<usize>,
  900}
  901
  902impl ChangeList {
  903    pub fn new() -> Self {
  904        Self {
  905            changes: Vec::new(),
  906            position: None,
  907        }
  908    }
  909
  910    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  911    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  912    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  913        if self.changes.is_empty() {
  914            return None;
  915        }
  916
  917        let prev = self.position.unwrap_or(self.changes.len());
  918        let next = if direction == Direction::Prev {
  919            prev.saturating_sub(count)
  920        } else {
  921            (prev + count).min(self.changes.len() - 1)
  922        };
  923        self.position = Some(next);
  924        self.changes.get(next).map(|change| change.locations())
  925    }
  926
  927    /// Adds a new change to the list, resetting the change list position.
  928    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  929        self.position.take();
  930        if let Some(last) = self.changes.last_mut()
  931            && group
  932        {
  933            last.current = Some(new_positions)
  934        } else {
  935            self.changes.push(ChangeLocation {
  936                original: new_positions,
  937                current: None,
  938            });
  939        }
  940    }
  941
  942    pub fn last(&self) -> Option<&[Anchor]> {
  943        self.changes.last().map(|change| change.locations())
  944    }
  945
  946    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  947        self.changes.last().map(|change| change.original.as_slice())
  948    }
  949
  950    pub fn invert_last_group(&mut self) {
  951        if let Some(last) = self.changes.last_mut()
  952            && let Some(current) = last.current.as_mut()
  953        {
  954            mem::swap(&mut last.original, current);
  955        }
  956    }
  957}
  958
  959#[derive(Clone)]
  960struct InlineBlamePopoverState {
  961    scroll_handle: ScrollHandle,
  962    commit_message: Option<ParsedCommitMessage>,
  963    markdown: Entity<Markdown>,
  964}
  965
  966struct InlineBlamePopover {
  967    position: gpui::Point<Pixels>,
  968    hide_task: Option<Task<()>>,
  969    popover_bounds: Option<Bounds<Pixels>>,
  970    popover_state: InlineBlamePopoverState,
  971    keyboard_grace: bool,
  972}
  973
  974enum SelectionDragState {
  975    /// State when no drag related activity is detected.
  976    None,
  977    /// State when the mouse is down on a selection that is about to be dragged.
  978    ReadyToDrag {
  979        selection: Selection<Anchor>,
  980        click_position: gpui::Point<Pixels>,
  981        mouse_down_time: Instant,
  982    },
  983    /// State when the mouse is dragging the selection in the editor.
  984    Dragging {
  985        selection: Selection<Anchor>,
  986        drop_cursor: Selection<Anchor>,
  987        hide_drop_cursor: bool,
  988    },
  989}
  990
  991enum ColumnarSelectionState {
  992    FromMouse {
  993        selection_tail: Anchor,
  994        display_point: Option<DisplayPoint>,
  995    },
  996    FromSelection {
  997        selection_tail: Anchor,
  998    },
  999}
 1000
 1001/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1002/// a breakpoint on them.
 1003#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1004struct PhantomBreakpointIndicator {
 1005    display_row: DisplayRow,
 1006    /// There's a small debounce between hovering over the line and showing the indicator.
 1007    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1008    is_active: bool,
 1009    collides_with_existing_breakpoint: bool,
 1010}
 1011
 1012/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1013///
 1014/// See the [module level documentation](self) for more information.
 1015pub struct Editor {
 1016    focus_handle: FocusHandle,
 1017    last_focused_descendant: Option<WeakFocusHandle>,
 1018    /// The text buffer being edited
 1019    buffer: Entity<MultiBuffer>,
 1020    /// Map of how text in the buffer should be displayed.
 1021    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1022    pub display_map: Entity<DisplayMap>,
 1023    placeholder_display_map: Option<Entity<DisplayMap>>,
 1024    pub selections: SelectionsCollection,
 1025    pub scroll_manager: ScrollManager,
 1026    /// When inline assist editors are linked, they all render cursors because
 1027    /// typing enters text into each of them, even the ones that aren't focused.
 1028    pub(crate) show_cursor_when_unfocused: bool,
 1029    columnar_selection_state: Option<ColumnarSelectionState>,
 1030    add_selections_state: Option<AddSelectionsState>,
 1031    select_next_state: Option<SelectNextState>,
 1032    select_prev_state: Option<SelectNextState>,
 1033    selection_history: SelectionHistory,
 1034    defer_selection_effects: bool,
 1035    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1036    autoclose_regions: Vec<AutocloseRegion>,
 1037    snippet_stack: InvalidationStack<SnippetState>,
 1038    select_syntax_node_history: SelectSyntaxNodeHistory,
 1039    ime_transaction: Option<TransactionId>,
 1040    pub diagnostics_max_severity: DiagnosticSeverity,
 1041    active_diagnostics: ActiveDiagnostic,
 1042    show_inline_diagnostics: bool,
 1043    inline_diagnostics_update: Task<()>,
 1044    inline_diagnostics_enabled: bool,
 1045    diagnostics_enabled: bool,
 1046    word_completions_enabled: bool,
 1047    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1048    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1049    hard_wrap: Option<usize>,
 1050    project: Option<Entity<Project>>,
 1051    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1052    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1053    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1054    blink_manager: Entity<BlinkManager>,
 1055    show_cursor_names: bool,
 1056    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1057    pub show_local_selections: bool,
 1058    mode: EditorMode,
 1059    show_breadcrumbs: bool,
 1060    show_gutter: bool,
 1061    show_scrollbars: ScrollbarAxes,
 1062    minimap_visibility: MinimapVisibility,
 1063    offset_content: bool,
 1064    disable_expand_excerpt_buttons: bool,
 1065    show_line_numbers: Option<bool>,
 1066    use_relative_line_numbers: Option<bool>,
 1067    show_git_diff_gutter: Option<bool>,
 1068    show_code_actions: Option<bool>,
 1069    show_runnables: Option<bool>,
 1070    show_breakpoints: Option<bool>,
 1071    show_wrap_guides: Option<bool>,
 1072    show_indent_guides: Option<bool>,
 1073    highlight_order: usize,
 1074    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1075    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1076    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1077    scrollbar_marker_state: ScrollbarMarkerState,
 1078    active_indent_guides_state: ActiveIndentGuidesState,
 1079    nav_history: Option<ItemNavHistory>,
 1080    context_menu: RefCell<Option<CodeContextMenu>>,
 1081    context_menu_options: Option<ContextMenuOptions>,
 1082    mouse_context_menu: Option<MouseContextMenu>,
 1083    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1084    inline_blame_popover: Option<InlineBlamePopover>,
 1085    inline_blame_popover_show_task: Option<Task<()>>,
 1086    signature_help_state: SignatureHelpState,
 1087    auto_signature_help: Option<bool>,
 1088    find_all_references_task_sources: Vec<Anchor>,
 1089    next_completion_id: CompletionId,
 1090    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1091    code_actions_task: Option<Task<Result<()>>>,
 1092    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1093    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1094    document_highlights_task: Option<Task<()>>,
 1095    linked_editing_range_task: Option<Task<Option<()>>>,
 1096    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1097    pending_rename: Option<RenameState>,
 1098    searchable: bool,
 1099    cursor_shape: CursorShape,
 1100    current_line_highlight: Option<CurrentLineHighlight>,
 1101    pub collapse_matches: bool,
 1102    autoindent_mode: Option<AutoindentMode>,
 1103    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1104    input_enabled: bool,
 1105    use_modal_editing: bool,
 1106    read_only: bool,
 1107    leader_id: Option<CollaboratorId>,
 1108    remote_id: Option<ViewId>,
 1109    pub hover_state: HoverState,
 1110    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1111    gutter_hovered: bool,
 1112    hovered_link_state: Option<HoveredLinkState>,
 1113    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1114    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1115    active_edit_prediction: Option<EditPredictionState>,
 1116    /// Used to prevent flickering as the user types while the menu is open
 1117    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1118    edit_prediction_settings: EditPredictionSettings,
 1119    edit_predictions_hidden_for_vim_mode: bool,
 1120    show_edit_predictions_override: Option<bool>,
 1121    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1122    edit_prediction_preview: EditPredictionPreview,
 1123    edit_prediction_indent_conflict: bool,
 1124    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1125    next_inlay_id: usize,
 1126    next_color_inlay_id: usize,
 1127    _subscriptions: Vec<Subscription>,
 1128    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1129    gutter_dimensions: GutterDimensions,
 1130    style: Option<EditorStyle>,
 1131    text_style_refinement: Option<TextStyleRefinement>,
 1132    next_editor_action_id: EditorActionId,
 1133    editor_actions: Rc<
 1134        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1135    >,
 1136    use_autoclose: bool,
 1137    use_auto_surround: bool,
 1138    auto_replace_emoji_shortcode: bool,
 1139    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1140    show_git_blame_gutter: bool,
 1141    show_git_blame_inline: bool,
 1142    show_git_blame_inline_delay_task: Option<Task<()>>,
 1143    git_blame_inline_enabled: bool,
 1144    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1145    buffer_serialization: Option<BufferSerialization>,
 1146    show_selection_menu: Option<bool>,
 1147    blame: Option<Entity<GitBlame>>,
 1148    blame_subscription: Option<Subscription>,
 1149    custom_context_menu: Option<
 1150        Box<
 1151            dyn 'static
 1152                + Fn(
 1153                    &mut Self,
 1154                    DisplayPoint,
 1155                    &mut Window,
 1156                    &mut Context<Self>,
 1157                ) -> Option<Entity<ui::ContextMenu>>,
 1158        >,
 1159    >,
 1160    last_bounds: Option<Bounds<Pixels>>,
 1161    last_position_map: Option<Rc<PositionMap>>,
 1162    expect_bounds_change: Option<Bounds<Pixels>>,
 1163    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1164    tasks_update_task: Option<Task<()>>,
 1165    breakpoint_store: Option<Entity<BreakpointStore>>,
 1166    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1167    hovered_diff_hunk_row: Option<DisplayRow>,
 1168    pull_diagnostics_task: Task<()>,
 1169    in_project_search: bool,
 1170    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1171    breadcrumb_header: Option<String>,
 1172    focused_block: Option<FocusedBlock>,
 1173    next_scroll_position: NextScrollCursorCenterTopBottom,
 1174    addons: HashMap<TypeId, Box<dyn Addon>>,
 1175    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1176    load_diff_task: Option<Shared<Task<()>>>,
 1177    /// Whether we are temporarily displaying a diff other than git's
 1178    temporary_diff_override: bool,
 1179    selection_mark_mode: bool,
 1180    toggle_fold_multiple_buffers: Task<()>,
 1181    _scroll_cursor_center_top_bottom_task: Task<()>,
 1182    serialize_selections: Task<()>,
 1183    serialize_folds: Task<()>,
 1184    mouse_cursor_hidden: bool,
 1185    minimap: Option<Entity<Self>>,
 1186    hide_mouse_mode: HideMouseMode,
 1187    pub change_list: ChangeList,
 1188    inline_value_cache: InlineValueCache,
 1189
 1190    selection_drag_state: SelectionDragState,
 1191    colors: Option<LspColorData>,
 1192    post_scroll_update: Task<()>,
 1193    refresh_colors_task: Task<()>,
 1194    inlay_hints: Option<LspInlayHintData>,
 1195    folding_newlines: Task<()>,
 1196    select_next_is_case_sensitive: Option<bool>,
 1197    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1198    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1199    accent_overrides: Vec<SharedString>,
 1200    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1201}
 1202
 1203fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1204    if debounce_ms > 0 {
 1205        Some(Duration::from_millis(debounce_ms))
 1206    } else {
 1207        None
 1208    }
 1209}
 1210
 1211#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1212enum NextScrollCursorCenterTopBottom {
 1213    #[default]
 1214    Center,
 1215    Top,
 1216    Bottom,
 1217}
 1218
 1219impl NextScrollCursorCenterTopBottom {
 1220    fn next(&self) -> Self {
 1221        match self {
 1222            Self::Center => Self::Top,
 1223            Self::Top => Self::Bottom,
 1224            Self::Bottom => Self::Center,
 1225        }
 1226    }
 1227}
 1228
 1229#[derive(Clone)]
 1230pub struct EditorSnapshot {
 1231    pub mode: EditorMode,
 1232    show_gutter: bool,
 1233    show_line_numbers: Option<bool>,
 1234    show_git_diff_gutter: Option<bool>,
 1235    show_code_actions: Option<bool>,
 1236    show_runnables: Option<bool>,
 1237    show_breakpoints: Option<bool>,
 1238    git_blame_gutter_max_author_length: Option<usize>,
 1239    pub display_snapshot: DisplaySnapshot,
 1240    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1241    is_focused: bool,
 1242    scroll_anchor: ScrollAnchor,
 1243    ongoing_scroll: OngoingScroll,
 1244    current_line_highlight: CurrentLineHighlight,
 1245    gutter_hovered: bool,
 1246}
 1247
 1248#[derive(Default, Debug, Clone, Copy)]
 1249pub struct GutterDimensions {
 1250    pub left_padding: Pixels,
 1251    pub right_padding: Pixels,
 1252    pub width: Pixels,
 1253    pub margin: Pixels,
 1254    pub git_blame_entries_width: Option<Pixels>,
 1255}
 1256
 1257impl GutterDimensions {
 1258    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1259        Self {
 1260            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1261            ..Default::default()
 1262        }
 1263    }
 1264
 1265    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1266        -cx.text_system().descent(font_id, font_size)
 1267    }
 1268    /// The full width of the space taken up by the gutter.
 1269    pub fn full_width(&self) -> Pixels {
 1270        self.margin + self.width
 1271    }
 1272
 1273    /// The width of the space reserved for the fold indicators,
 1274    /// use alongside 'justify_end' and `gutter_width` to
 1275    /// right align content with the line numbers
 1276    pub fn fold_area_width(&self) -> Pixels {
 1277        self.margin + self.right_padding
 1278    }
 1279}
 1280
 1281struct CharacterDimensions {
 1282    em_width: Pixels,
 1283    em_advance: Pixels,
 1284    line_height: Pixels,
 1285}
 1286
 1287#[derive(Debug)]
 1288pub struct RemoteSelection {
 1289    pub replica_id: ReplicaId,
 1290    pub selection: Selection<Anchor>,
 1291    pub cursor_shape: CursorShape,
 1292    pub collaborator_id: CollaboratorId,
 1293    pub line_mode: bool,
 1294    pub user_name: Option<SharedString>,
 1295    pub color: PlayerColor,
 1296}
 1297
 1298#[derive(Clone, Debug)]
 1299struct SelectionHistoryEntry {
 1300    selections: Arc<[Selection<Anchor>]>,
 1301    select_next_state: Option<SelectNextState>,
 1302    select_prev_state: Option<SelectNextState>,
 1303    add_selections_state: Option<AddSelectionsState>,
 1304}
 1305
 1306#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1307enum SelectionHistoryMode {
 1308    #[default]
 1309    Normal,
 1310    Undoing,
 1311    Redoing,
 1312    Skipping,
 1313}
 1314
 1315#[derive(Clone, PartialEq, Eq, Hash)]
 1316struct HoveredCursor {
 1317    replica_id: ReplicaId,
 1318    selection_id: usize,
 1319}
 1320
 1321#[derive(Debug)]
 1322/// SelectionEffects controls the side-effects of updating the selection.
 1323///
 1324/// The default behaviour does "what you mostly want":
 1325/// - it pushes to the nav history if the cursor moved by >10 lines
 1326/// - it re-triggers completion requests
 1327/// - it scrolls to fit
 1328///
 1329/// You might want to modify these behaviours. For example when doing a "jump"
 1330/// like go to definition, we always want to add to nav history; but when scrolling
 1331/// in vim mode we never do.
 1332///
 1333/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1334/// move.
 1335#[derive(Clone)]
 1336pub struct SelectionEffects {
 1337    nav_history: Option<bool>,
 1338    completions: bool,
 1339    scroll: Option<Autoscroll>,
 1340}
 1341
 1342impl Default for SelectionEffects {
 1343    fn default() -> Self {
 1344        Self {
 1345            nav_history: None,
 1346            completions: true,
 1347            scroll: Some(Autoscroll::fit()),
 1348        }
 1349    }
 1350}
 1351impl SelectionEffects {
 1352    pub fn scroll(scroll: Autoscroll) -> Self {
 1353        Self {
 1354            scroll: Some(scroll),
 1355            ..Default::default()
 1356        }
 1357    }
 1358
 1359    pub fn no_scroll() -> Self {
 1360        Self {
 1361            scroll: None,
 1362            ..Default::default()
 1363        }
 1364    }
 1365
 1366    pub fn completions(self, completions: bool) -> Self {
 1367        Self {
 1368            completions,
 1369            ..self
 1370        }
 1371    }
 1372
 1373    pub fn nav_history(self, nav_history: bool) -> Self {
 1374        Self {
 1375            nav_history: Some(nav_history),
 1376            ..self
 1377        }
 1378    }
 1379}
 1380
 1381struct DeferredSelectionEffectsState {
 1382    changed: bool,
 1383    effects: SelectionEffects,
 1384    old_cursor_position: Anchor,
 1385    history_entry: SelectionHistoryEntry,
 1386}
 1387
 1388#[derive(Default)]
 1389struct SelectionHistory {
 1390    #[allow(clippy::type_complexity)]
 1391    selections_by_transaction:
 1392        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1393    mode: SelectionHistoryMode,
 1394    undo_stack: VecDeque<SelectionHistoryEntry>,
 1395    redo_stack: VecDeque<SelectionHistoryEntry>,
 1396}
 1397
 1398impl SelectionHistory {
 1399    #[track_caller]
 1400    fn insert_transaction(
 1401        &mut self,
 1402        transaction_id: TransactionId,
 1403        selections: Arc<[Selection<Anchor>]>,
 1404    ) {
 1405        if selections.is_empty() {
 1406            log::error!(
 1407                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1408                std::panic::Location::caller()
 1409            );
 1410            return;
 1411        }
 1412        self.selections_by_transaction
 1413            .insert(transaction_id, (selections, None));
 1414    }
 1415
 1416    #[allow(clippy::type_complexity)]
 1417    fn transaction(
 1418        &self,
 1419        transaction_id: TransactionId,
 1420    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1421        self.selections_by_transaction.get(&transaction_id)
 1422    }
 1423
 1424    #[allow(clippy::type_complexity)]
 1425    fn transaction_mut(
 1426        &mut self,
 1427        transaction_id: TransactionId,
 1428    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1429        self.selections_by_transaction.get_mut(&transaction_id)
 1430    }
 1431
 1432    fn push(&mut self, entry: SelectionHistoryEntry) {
 1433        if !entry.selections.is_empty() {
 1434            match self.mode {
 1435                SelectionHistoryMode::Normal => {
 1436                    self.push_undo(entry);
 1437                    self.redo_stack.clear();
 1438                }
 1439                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1440                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1441                SelectionHistoryMode::Skipping => {}
 1442            }
 1443        }
 1444    }
 1445
 1446    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1447        if self
 1448            .undo_stack
 1449            .back()
 1450            .is_none_or(|e| e.selections != entry.selections)
 1451        {
 1452            self.undo_stack.push_back(entry);
 1453            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1454                self.undo_stack.pop_front();
 1455            }
 1456        }
 1457    }
 1458
 1459    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1460        if self
 1461            .redo_stack
 1462            .back()
 1463            .is_none_or(|e| e.selections != entry.selections)
 1464        {
 1465            self.redo_stack.push_back(entry);
 1466            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1467                self.redo_stack.pop_front();
 1468            }
 1469        }
 1470    }
 1471}
 1472
 1473#[derive(Clone, Copy)]
 1474pub struct RowHighlightOptions {
 1475    pub autoscroll: bool,
 1476    pub include_gutter: bool,
 1477}
 1478
 1479impl Default for RowHighlightOptions {
 1480    fn default() -> Self {
 1481        Self {
 1482            autoscroll: Default::default(),
 1483            include_gutter: true,
 1484        }
 1485    }
 1486}
 1487
 1488struct RowHighlight {
 1489    index: usize,
 1490    range: Range<Anchor>,
 1491    color: Hsla,
 1492    options: RowHighlightOptions,
 1493    type_id: TypeId,
 1494}
 1495
 1496#[derive(Clone, Debug)]
 1497struct AddSelectionsState {
 1498    groups: Vec<AddSelectionsGroup>,
 1499}
 1500
 1501#[derive(Clone, Debug)]
 1502struct AddSelectionsGroup {
 1503    above: bool,
 1504    stack: Vec<usize>,
 1505}
 1506
 1507#[derive(Clone)]
 1508struct SelectNextState {
 1509    query: AhoCorasick,
 1510    wordwise: bool,
 1511    done: bool,
 1512}
 1513
 1514impl std::fmt::Debug for SelectNextState {
 1515    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1516        f.debug_struct(std::any::type_name::<Self>())
 1517            .field("wordwise", &self.wordwise)
 1518            .field("done", &self.done)
 1519            .finish()
 1520    }
 1521}
 1522
 1523#[derive(Debug)]
 1524struct AutocloseRegion {
 1525    selection_id: usize,
 1526    range: Range<Anchor>,
 1527    pair: BracketPair,
 1528}
 1529
 1530#[derive(Debug)]
 1531struct SnippetState {
 1532    ranges: Vec<Vec<Range<Anchor>>>,
 1533    active_index: usize,
 1534    choices: Vec<Option<Vec<String>>>,
 1535}
 1536
 1537#[doc(hidden)]
 1538pub struct RenameState {
 1539    pub range: Range<Anchor>,
 1540    pub old_name: Arc<str>,
 1541    pub editor: Entity<Editor>,
 1542    block_id: CustomBlockId,
 1543}
 1544
 1545struct InvalidationStack<T>(Vec<T>);
 1546
 1547struct RegisteredEditPredictionProvider {
 1548    provider: Arc<dyn EditPredictionProviderHandle>,
 1549    _subscription: Subscription,
 1550}
 1551
 1552#[derive(Debug, PartialEq, Eq)]
 1553pub struct ActiveDiagnosticGroup {
 1554    pub active_range: Range<Anchor>,
 1555    pub active_message: String,
 1556    pub group_id: usize,
 1557    pub blocks: HashSet<CustomBlockId>,
 1558}
 1559
 1560#[derive(Debug, PartialEq, Eq)]
 1561
 1562pub(crate) enum ActiveDiagnostic {
 1563    None,
 1564    All,
 1565    Group(ActiveDiagnosticGroup),
 1566}
 1567
 1568#[derive(Serialize, Deserialize, Clone, Debug)]
 1569pub struct ClipboardSelection {
 1570    /// The number of bytes in this selection.
 1571    pub len: usize,
 1572    /// Whether this was a full-line selection.
 1573    pub is_entire_line: bool,
 1574    /// The indentation of the first line when this content was originally copied.
 1575    pub first_line_indent: u32,
 1576}
 1577
 1578// selections, scroll behavior, was newest selection reversed
 1579type SelectSyntaxNodeHistoryState = (
 1580    Box<[Selection<MultiBufferOffset>]>,
 1581    SelectSyntaxNodeScrollBehavior,
 1582    bool,
 1583);
 1584
 1585#[derive(Default)]
 1586struct SelectSyntaxNodeHistory {
 1587    stack: Vec<SelectSyntaxNodeHistoryState>,
 1588    // disable temporarily to allow changing selections without losing the stack
 1589    pub disable_clearing: bool,
 1590}
 1591
 1592impl SelectSyntaxNodeHistory {
 1593    pub fn try_clear(&mut self) {
 1594        if !self.disable_clearing {
 1595            self.stack.clear();
 1596        }
 1597    }
 1598
 1599    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1600        self.stack.push(selection);
 1601    }
 1602
 1603    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1604        self.stack.pop()
 1605    }
 1606}
 1607
 1608enum SelectSyntaxNodeScrollBehavior {
 1609    CursorTop,
 1610    FitSelection,
 1611    CursorBottom,
 1612}
 1613
 1614#[derive(Debug)]
 1615pub(crate) struct NavigationData {
 1616    cursor_anchor: Anchor,
 1617    cursor_position: Point,
 1618    scroll_anchor: ScrollAnchor,
 1619    scroll_top_row: u32,
 1620}
 1621
 1622#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1623pub enum GotoDefinitionKind {
 1624    Symbol,
 1625    Declaration,
 1626    Type,
 1627    Implementation,
 1628}
 1629
 1630pub enum FormatTarget {
 1631    Buffers(HashSet<Entity<Buffer>>),
 1632    Ranges(Vec<Range<MultiBufferPoint>>),
 1633}
 1634
 1635pub(crate) struct FocusedBlock {
 1636    id: BlockId,
 1637    focus_handle: WeakFocusHandle,
 1638}
 1639
 1640#[derive(Clone)]
 1641enum JumpData {
 1642    MultiBufferRow {
 1643        row: MultiBufferRow,
 1644        line_offset_from_top: u32,
 1645    },
 1646    MultiBufferPoint {
 1647        excerpt_id: ExcerptId,
 1648        position: Point,
 1649        anchor: text::Anchor,
 1650        line_offset_from_top: u32,
 1651    },
 1652}
 1653
 1654pub enum MultibufferSelectionMode {
 1655    First,
 1656    All,
 1657}
 1658
 1659#[derive(Clone, Copy, Debug, Default)]
 1660pub struct RewrapOptions {
 1661    pub override_language_settings: bool,
 1662    pub preserve_existing_whitespace: bool,
 1663}
 1664
 1665impl Editor {
 1666    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1667        let buffer = cx.new(|cx| Buffer::local("", cx));
 1668        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1669        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1670    }
 1671
 1672    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1673        let buffer = cx.new(|cx| Buffer::local("", cx));
 1674        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1675        Self::new(EditorMode::full(), buffer, None, window, cx)
 1676    }
 1677
 1678    pub fn auto_height(
 1679        min_lines: usize,
 1680        max_lines: usize,
 1681        window: &mut Window,
 1682        cx: &mut Context<Self>,
 1683    ) -> Self {
 1684        let buffer = cx.new(|cx| Buffer::local("", cx));
 1685        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1686        Self::new(
 1687            EditorMode::AutoHeight {
 1688                min_lines,
 1689                max_lines: Some(max_lines),
 1690            },
 1691            buffer,
 1692            None,
 1693            window,
 1694            cx,
 1695        )
 1696    }
 1697
 1698    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1699    /// The editor grows as tall as needed to fit its content.
 1700    pub fn auto_height_unbounded(
 1701        min_lines: usize,
 1702        window: &mut Window,
 1703        cx: &mut Context<Self>,
 1704    ) -> Self {
 1705        let buffer = cx.new(|cx| Buffer::local("", cx));
 1706        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1707        Self::new(
 1708            EditorMode::AutoHeight {
 1709                min_lines,
 1710                max_lines: None,
 1711            },
 1712            buffer,
 1713            None,
 1714            window,
 1715            cx,
 1716        )
 1717    }
 1718
 1719    pub fn for_buffer(
 1720        buffer: Entity<Buffer>,
 1721        project: Option<Entity<Project>>,
 1722        window: &mut Window,
 1723        cx: &mut Context<Self>,
 1724    ) -> Self {
 1725        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1726        Self::new(EditorMode::full(), buffer, project, window, cx)
 1727    }
 1728
 1729    pub fn for_multibuffer(
 1730        buffer: Entity<MultiBuffer>,
 1731        project: Option<Entity<Project>>,
 1732        window: &mut Window,
 1733        cx: &mut Context<Self>,
 1734    ) -> Self {
 1735        Self::new(EditorMode::full(), buffer, project, window, cx)
 1736    }
 1737
 1738    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1739        let mut clone = Self::new(
 1740            self.mode.clone(),
 1741            self.buffer.clone(),
 1742            self.project.clone(),
 1743            window,
 1744            cx,
 1745        );
 1746        self.display_map.update(cx, |display_map, cx| {
 1747            let snapshot = display_map.snapshot(cx);
 1748            clone.display_map.update(cx, |display_map, cx| {
 1749                display_map.set_state(&snapshot, cx);
 1750            });
 1751        });
 1752        clone.folds_did_change(cx);
 1753        clone.selections.clone_state(&self.selections);
 1754        clone.scroll_manager.clone_state(&self.scroll_manager);
 1755        clone.searchable = self.searchable;
 1756        clone.read_only = self.read_only;
 1757        clone
 1758    }
 1759
 1760    pub fn new(
 1761        mode: EditorMode,
 1762        buffer: Entity<MultiBuffer>,
 1763        project: Option<Entity<Project>>,
 1764        window: &mut Window,
 1765        cx: &mut Context<Self>,
 1766    ) -> Self {
 1767        Editor::new_internal(mode, buffer, project, None, window, cx)
 1768    }
 1769
 1770    pub fn sticky_headers(&self, cx: &App) -> Option<Vec<OutlineItem<Anchor>>> {
 1771        let multi_buffer = self.buffer().read(cx);
 1772        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1773        let multi_buffer_visible_start = self
 1774            .scroll_manager
 1775            .anchor()
 1776            .anchor
 1777            .to_point(&multi_buffer_snapshot);
 1778        let max_row = multi_buffer_snapshot.max_point().row;
 1779
 1780        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1781        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1782
 1783        if let Some((excerpt_id, buffer_id, buffer)) = multi_buffer.read(cx).as_singleton() {
 1784            let outline_items = buffer
 1785                .outline_items_containing(
 1786                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1787                    true,
 1788                    self.style().map(|style| style.syntax.as_ref()),
 1789                )
 1790                .into_iter()
 1791                .map(|outline_item| OutlineItem {
 1792                    depth: outline_item.depth,
 1793                    range: Anchor::range_in_buffer(*excerpt_id, buffer_id, outline_item.range),
 1794                    source_range_for_text: Anchor::range_in_buffer(
 1795                        *excerpt_id,
 1796                        buffer_id,
 1797                        outline_item.source_range_for_text,
 1798                    ),
 1799                    text: outline_item.text,
 1800                    highlight_ranges: outline_item.highlight_ranges,
 1801                    name_ranges: outline_item.name_ranges,
 1802                    body_range: outline_item
 1803                        .body_range
 1804                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1805                    annotation_range: outline_item
 1806                        .annotation_range
 1807                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1808                });
 1809            return Some(outline_items.collect());
 1810        }
 1811
 1812        None
 1813    }
 1814
 1815    fn new_internal(
 1816        mode: EditorMode,
 1817        multi_buffer: Entity<MultiBuffer>,
 1818        project: Option<Entity<Project>>,
 1819        display_map: Option<Entity<DisplayMap>>,
 1820        window: &mut Window,
 1821        cx: &mut Context<Self>,
 1822    ) -> Self {
 1823        debug_assert!(
 1824            display_map.is_none() || mode.is_minimap(),
 1825            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1826        );
 1827
 1828        let full_mode = mode.is_full();
 1829        let is_minimap = mode.is_minimap();
 1830        let diagnostics_max_severity = if full_mode {
 1831            EditorSettings::get_global(cx)
 1832                .diagnostics_max_severity
 1833                .unwrap_or(DiagnosticSeverity::Hint)
 1834        } else {
 1835            DiagnosticSeverity::Off
 1836        };
 1837        let style = window.text_style();
 1838        let font_size = style.font_size.to_pixels(window.rem_size());
 1839        let editor = cx.entity().downgrade();
 1840        let fold_placeholder = FoldPlaceholder {
 1841            constrain_width: false,
 1842            render: Arc::new(move |fold_id, fold_range, cx| {
 1843                let editor = editor.clone();
 1844                div()
 1845                    .id(fold_id)
 1846                    .bg(cx.theme().colors().ghost_element_background)
 1847                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1848                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1849                    .rounded_xs()
 1850                    .size_full()
 1851                    .cursor_pointer()
 1852                    .child("")
 1853                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1854                    .on_click(move |_, _window, cx| {
 1855                        editor
 1856                            .update(cx, |editor, cx| {
 1857                                editor.unfold_ranges(
 1858                                    &[fold_range.start..fold_range.end],
 1859                                    true,
 1860                                    false,
 1861                                    cx,
 1862                                );
 1863                                cx.stop_propagation();
 1864                            })
 1865                            .ok();
 1866                    })
 1867                    .into_any()
 1868            }),
 1869            merge_adjacent: true,
 1870            ..FoldPlaceholder::default()
 1871        };
 1872        let display_map = display_map.unwrap_or_else(|| {
 1873            cx.new(|cx| {
 1874                DisplayMap::new(
 1875                    multi_buffer.clone(),
 1876                    style.font(),
 1877                    font_size,
 1878                    None,
 1879                    FILE_HEADER_HEIGHT,
 1880                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1881                    fold_placeholder,
 1882                    diagnostics_max_severity,
 1883                    cx,
 1884                )
 1885            })
 1886        });
 1887
 1888        let selections = SelectionsCollection::new();
 1889
 1890        let blink_manager = cx.new(|cx| {
 1891            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1892            if is_minimap {
 1893                blink_manager.disable(cx);
 1894            }
 1895            blink_manager
 1896        });
 1897
 1898        let soft_wrap_mode_override =
 1899            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1900
 1901        let mut project_subscriptions = Vec::new();
 1902        if full_mode && let Some(project) = project.as_ref() {
 1903            project_subscriptions.push(cx.subscribe_in(
 1904                project,
 1905                window,
 1906                |editor, _, event, window, cx| match event {
 1907                    project::Event::RefreshCodeLens => {
 1908                        // we always query lens with actions, without storing them, always refreshing them
 1909                    }
 1910                    project::Event::RefreshInlayHints {
 1911                        server_id,
 1912                        request_id,
 1913                    } => {
 1914                        editor.refresh_inlay_hints(
 1915                            InlayHintRefreshReason::RefreshRequested {
 1916                                server_id: *server_id,
 1917                                request_id: *request_id,
 1918                            },
 1919                            cx,
 1920                        );
 1921                    }
 1922                    project::Event::LanguageServerRemoved(..) => {
 1923                        if editor.tasks_update_task.is_none() {
 1924                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1925                        }
 1926                        editor.registered_buffers.clear();
 1927                        editor.register_visible_buffers(cx);
 1928                    }
 1929                    project::Event::LanguageServerAdded(..) => {
 1930                        if editor.tasks_update_task.is_none() {
 1931                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1932                        }
 1933                    }
 1934                    project::Event::SnippetEdit(id, snippet_edits) => {
 1935                        // todo(lw): Non singletons
 1936                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 1937                            let snapshot = buffer.read(cx).snapshot();
 1938                            let focus_handle = editor.focus_handle(cx);
 1939                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 1940                                for (range, snippet) in snippet_edits {
 1941                                    let buffer_range =
 1942                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1943                                    editor
 1944                                        .insert_snippet(
 1945                                            &[MultiBufferOffset(buffer_range.start)
 1946                                                ..MultiBufferOffset(buffer_range.end)],
 1947                                            snippet.clone(),
 1948                                            window,
 1949                                            cx,
 1950                                        )
 1951                                        .ok();
 1952                                }
 1953                            }
 1954                        }
 1955                    }
 1956                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1957                        let buffer_id = *buffer_id;
 1958                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1959                            editor.register_buffer(buffer_id, cx);
 1960                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1961                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1962                            refresh_linked_ranges(editor, window, cx);
 1963                            editor.refresh_code_actions(window, cx);
 1964                            editor.refresh_document_highlights(cx);
 1965                        }
 1966                    }
 1967
 1968                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1969                        let Some(workspace) = editor.workspace() else {
 1970                            return;
 1971                        };
 1972                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1973                        else {
 1974                            return;
 1975                        };
 1976
 1977                        if active_editor.entity_id() == cx.entity_id() {
 1978                            let entity_id = cx.entity_id();
 1979                            workspace.update(cx, |this, cx| {
 1980                                this.panes_mut()
 1981                                    .iter_mut()
 1982                                    .filter(|pane| pane.entity_id() != entity_id)
 1983                                    .for_each(|p| {
 1984                                        p.update(cx, |pane, _| {
 1985                                            pane.nav_history_mut().rename_item(
 1986                                                entity_id,
 1987                                                project_path.clone(),
 1988                                                abs_path.clone().into(),
 1989                                            );
 1990                                        })
 1991                                    });
 1992                            });
 1993                            let edited_buffers_already_open = {
 1994                                let other_editors: Vec<Entity<Editor>> = workspace
 1995                                    .read(cx)
 1996                                    .panes()
 1997                                    .iter()
 1998                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1999                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 2000                                    .collect();
 2001
 2002                                transaction.0.keys().all(|buffer| {
 2003                                    other_editors.iter().any(|editor| {
 2004                                        let multi_buffer = editor.read(cx).buffer();
 2005                                        multi_buffer.read(cx).is_singleton()
 2006                                            && multi_buffer.read(cx).as_singleton().map_or(
 2007                                                false,
 2008                                                |singleton| {
 2009                                                    singleton.entity_id() == buffer.entity_id()
 2010                                                },
 2011                                            )
 2012                                    })
 2013                                })
 2014                            };
 2015                            if !edited_buffers_already_open {
 2016                                let workspace = workspace.downgrade();
 2017                                let transaction = transaction.clone();
 2018                                cx.defer_in(window, move |_, window, cx| {
 2019                                    cx.spawn_in(window, async move |editor, cx| {
 2020                                        Self::open_project_transaction(
 2021                                            &editor,
 2022                                            workspace,
 2023                                            transaction,
 2024                                            "Rename".to_string(),
 2025                                            cx,
 2026                                        )
 2027                                        .await
 2028                                        .ok()
 2029                                    })
 2030                                    .detach();
 2031                                });
 2032                            }
 2033                        }
 2034                    }
 2035
 2036                    _ => {}
 2037                },
 2038            ));
 2039            if let Some(task_inventory) = project
 2040                .read(cx)
 2041                .task_store()
 2042                .read(cx)
 2043                .task_inventory()
 2044                .cloned()
 2045            {
 2046                project_subscriptions.push(cx.observe_in(
 2047                    &task_inventory,
 2048                    window,
 2049                    |editor, _, window, cx| {
 2050                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2051                    },
 2052                ));
 2053            };
 2054
 2055            project_subscriptions.push(cx.subscribe_in(
 2056                &project.read(cx).breakpoint_store(),
 2057                window,
 2058                |editor, _, event, window, cx| match event {
 2059                    BreakpointStoreEvent::ClearDebugLines => {
 2060                        editor.clear_row_highlights::<ActiveDebugLine>();
 2061                        editor.refresh_inline_values(cx);
 2062                    }
 2063                    BreakpointStoreEvent::SetDebugLine => {
 2064                        if editor.go_to_active_debug_line(window, cx) {
 2065                            cx.stop_propagation();
 2066                        }
 2067
 2068                        editor.refresh_inline_values(cx);
 2069                    }
 2070                    _ => {}
 2071                },
 2072            ));
 2073            let git_store = project.read(cx).git_store().clone();
 2074            let project = project.clone();
 2075            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2076                if let GitStoreEvent::RepositoryAdded = event {
 2077                    this.load_diff_task = Some(
 2078                        update_uncommitted_diff_for_buffer(
 2079                            cx.entity(),
 2080                            &project,
 2081                            this.buffer.read(cx).all_buffers(),
 2082                            this.buffer.clone(),
 2083                            cx,
 2084                        )
 2085                        .shared(),
 2086                    );
 2087                }
 2088            }));
 2089        }
 2090
 2091        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2092
 2093        let inlay_hint_settings =
 2094            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2095        let focus_handle = cx.focus_handle();
 2096        if !is_minimap {
 2097            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2098                .detach();
 2099            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2100                .detach();
 2101            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2102                .detach();
 2103            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2104                .detach();
 2105            cx.observe_pending_input(window, Self::observe_pending_input)
 2106                .detach();
 2107        }
 2108
 2109        let show_indent_guides =
 2110            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2111                Some(false)
 2112            } else {
 2113                None
 2114            };
 2115
 2116        let breakpoint_store = match (&mode, project.as_ref()) {
 2117            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2118            _ => None,
 2119        };
 2120
 2121        let mut code_action_providers = Vec::new();
 2122        let mut load_uncommitted_diff = None;
 2123        if let Some(project) = project.clone() {
 2124            load_uncommitted_diff = Some(
 2125                update_uncommitted_diff_for_buffer(
 2126                    cx.entity(),
 2127                    &project,
 2128                    multi_buffer.read(cx).all_buffers(),
 2129                    multi_buffer.clone(),
 2130                    cx,
 2131                )
 2132                .shared(),
 2133            );
 2134            code_action_providers.push(Rc::new(project) as Rc<_>);
 2135        }
 2136
 2137        let mut editor = Self {
 2138            focus_handle,
 2139            show_cursor_when_unfocused: false,
 2140            last_focused_descendant: None,
 2141            buffer: multi_buffer.clone(),
 2142            display_map: display_map.clone(),
 2143            placeholder_display_map: None,
 2144            selections,
 2145            scroll_manager: ScrollManager::new(cx),
 2146            columnar_selection_state: None,
 2147            add_selections_state: None,
 2148            select_next_state: None,
 2149            select_prev_state: None,
 2150            selection_history: SelectionHistory::default(),
 2151            defer_selection_effects: false,
 2152            deferred_selection_effects_state: None,
 2153            autoclose_regions: Vec::new(),
 2154            snippet_stack: InvalidationStack::default(),
 2155            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2156            ime_transaction: None,
 2157            active_diagnostics: ActiveDiagnostic::None,
 2158            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2159            inline_diagnostics_update: Task::ready(()),
 2160            inline_diagnostics: Vec::new(),
 2161            soft_wrap_mode_override,
 2162            diagnostics_max_severity,
 2163            hard_wrap: None,
 2164            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2165            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2166            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2167            project,
 2168            blink_manager: blink_manager.clone(),
 2169            show_local_selections: true,
 2170            show_scrollbars: ScrollbarAxes {
 2171                horizontal: full_mode,
 2172                vertical: full_mode,
 2173            },
 2174            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2175            offset_content: !matches!(mode, EditorMode::SingleLine),
 2176            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2177            show_gutter: full_mode,
 2178            show_line_numbers: (!full_mode).then_some(false),
 2179            use_relative_line_numbers: None,
 2180            disable_expand_excerpt_buttons: !full_mode,
 2181            show_git_diff_gutter: None,
 2182            show_code_actions: None,
 2183            show_runnables: None,
 2184            show_breakpoints: None,
 2185            show_wrap_guides: None,
 2186            show_indent_guides,
 2187            highlight_order: 0,
 2188            highlighted_rows: HashMap::default(),
 2189            background_highlights: HashMap::default(),
 2190            gutter_highlights: HashMap::default(),
 2191            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2192            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2193            nav_history: None,
 2194            context_menu: RefCell::new(None),
 2195            context_menu_options: None,
 2196            mouse_context_menu: None,
 2197            completion_tasks: Vec::new(),
 2198            inline_blame_popover: None,
 2199            inline_blame_popover_show_task: None,
 2200            signature_help_state: SignatureHelpState::default(),
 2201            auto_signature_help: None,
 2202            find_all_references_task_sources: Vec::new(),
 2203            next_completion_id: 0,
 2204            next_inlay_id: 0,
 2205            code_action_providers,
 2206            available_code_actions: None,
 2207            code_actions_task: None,
 2208            quick_selection_highlight_task: None,
 2209            debounced_selection_highlight_task: None,
 2210            document_highlights_task: None,
 2211            linked_editing_range_task: None,
 2212            pending_rename: None,
 2213            searchable: !is_minimap,
 2214            cursor_shape: EditorSettings::get_global(cx)
 2215                .cursor_shape
 2216                .unwrap_or_default(),
 2217            current_line_highlight: None,
 2218            autoindent_mode: Some(AutoindentMode::EachLine),
 2219            collapse_matches: false,
 2220            workspace: None,
 2221            input_enabled: !is_minimap,
 2222            use_modal_editing: full_mode,
 2223            read_only: is_minimap,
 2224            use_autoclose: true,
 2225            use_auto_surround: true,
 2226            auto_replace_emoji_shortcode: false,
 2227            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2228            leader_id: None,
 2229            remote_id: None,
 2230            hover_state: HoverState::default(),
 2231            pending_mouse_down: None,
 2232            hovered_link_state: None,
 2233            edit_prediction_provider: None,
 2234            active_edit_prediction: None,
 2235            stale_edit_prediction_in_menu: None,
 2236            edit_prediction_preview: EditPredictionPreview::Inactive {
 2237                released_too_fast: false,
 2238            },
 2239            inline_diagnostics_enabled: full_mode,
 2240            diagnostics_enabled: full_mode,
 2241            word_completions_enabled: full_mode,
 2242            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2243            gutter_hovered: false,
 2244            pixel_position_of_newest_cursor: None,
 2245            last_bounds: None,
 2246            last_position_map: None,
 2247            expect_bounds_change: None,
 2248            gutter_dimensions: GutterDimensions::default(),
 2249            style: None,
 2250            show_cursor_names: false,
 2251            hovered_cursors: HashMap::default(),
 2252            next_editor_action_id: EditorActionId::default(),
 2253            editor_actions: Rc::default(),
 2254            edit_predictions_hidden_for_vim_mode: false,
 2255            show_edit_predictions_override: None,
 2256            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2257            edit_prediction_settings: EditPredictionSettings::Disabled,
 2258            edit_prediction_indent_conflict: false,
 2259            edit_prediction_requires_modifier_in_indent_conflict: true,
 2260            custom_context_menu: None,
 2261            show_git_blame_gutter: false,
 2262            show_git_blame_inline: false,
 2263            show_selection_menu: None,
 2264            show_git_blame_inline_delay_task: None,
 2265            git_blame_inline_enabled: full_mode
 2266                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2267            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2268            buffer_serialization: is_minimap.not().then(|| {
 2269                BufferSerialization::new(
 2270                    ProjectSettings::get_global(cx)
 2271                        .session
 2272                        .restore_unsaved_buffers,
 2273                )
 2274            }),
 2275            blame: None,
 2276            blame_subscription: None,
 2277            tasks: BTreeMap::default(),
 2278
 2279            breakpoint_store,
 2280            gutter_breakpoint_indicator: (None, None),
 2281            hovered_diff_hunk_row: None,
 2282            _subscriptions: (!is_minimap)
 2283                .then(|| {
 2284                    vec![
 2285                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2286                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2287                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2288                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2289                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2290                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2291                        cx.observe_window_activation(window, |editor, window, cx| {
 2292                            let active = window.is_window_active();
 2293                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2294                                if active {
 2295                                    blink_manager.enable(cx);
 2296                                } else {
 2297                                    blink_manager.disable(cx);
 2298                                }
 2299                            });
 2300                            if active {
 2301                                editor.show_mouse_cursor(cx);
 2302                            }
 2303                        }),
 2304                    ]
 2305                })
 2306                .unwrap_or_default(),
 2307            tasks_update_task: None,
 2308            pull_diagnostics_task: Task::ready(()),
 2309            colors: None,
 2310            refresh_colors_task: Task::ready(()),
 2311            inlay_hints: None,
 2312            next_color_inlay_id: 0,
 2313            post_scroll_update: Task::ready(()),
 2314            linked_edit_ranges: Default::default(),
 2315            in_project_search: false,
 2316            previous_search_ranges: None,
 2317            breadcrumb_header: None,
 2318            focused_block: None,
 2319            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2320            addons: HashMap::default(),
 2321            registered_buffers: HashMap::default(),
 2322            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2323            selection_mark_mode: false,
 2324            toggle_fold_multiple_buffers: Task::ready(()),
 2325            serialize_selections: Task::ready(()),
 2326            serialize_folds: Task::ready(()),
 2327            text_style_refinement: None,
 2328            load_diff_task: load_uncommitted_diff,
 2329            temporary_diff_override: false,
 2330            mouse_cursor_hidden: false,
 2331            minimap: None,
 2332            hide_mouse_mode: EditorSettings::get_global(cx)
 2333                .hide_mouse
 2334                .unwrap_or_default(),
 2335            change_list: ChangeList::new(),
 2336            mode,
 2337            selection_drag_state: SelectionDragState::None,
 2338            folding_newlines: Task::ready(()),
 2339            lookup_key: None,
 2340            select_next_is_case_sensitive: None,
 2341            applicable_language_settings: HashMap::default(),
 2342            accent_overrides: Vec::new(),
 2343            fetched_tree_sitter_chunks: HashMap::default(),
 2344        };
 2345
 2346        if is_minimap {
 2347            return editor;
 2348        }
 2349
 2350        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2351        editor.accent_overrides = editor.fetch_accent_overrides(cx);
 2352
 2353        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2354            editor
 2355                ._subscriptions
 2356                .push(cx.observe(breakpoints, |_, _, cx| {
 2357                    cx.notify();
 2358                }));
 2359        }
 2360        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2361        editor._subscriptions.extend(project_subscriptions);
 2362
 2363        editor._subscriptions.push(cx.subscribe_in(
 2364            &cx.entity(),
 2365            window,
 2366            |editor, _, e: &EditorEvent, window, cx| match e {
 2367                EditorEvent::ScrollPositionChanged { local, .. } => {
 2368                    if *local {
 2369                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2370                        editor.inline_blame_popover.take();
 2371                        let new_anchor = editor.scroll_manager.anchor();
 2372                        let snapshot = editor.snapshot(window, cx);
 2373                        editor.update_restoration_data(cx, move |data| {
 2374                            data.scroll_position = (
 2375                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2376                                new_anchor.offset,
 2377                            );
 2378                        });
 2379
 2380                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2381                            cx.background_executor()
 2382                                .timer(Duration::from_millis(50))
 2383                                .await;
 2384                            editor
 2385                                .update_in(cx, |editor, window, cx| {
 2386                                    editor.register_visible_buffers(cx);
 2387                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2388                                    editor.refresh_inlay_hints(
 2389                                        InlayHintRefreshReason::NewLinesShown,
 2390                                        cx,
 2391                                    );
 2392                                    editor.colorize_brackets(false, cx);
 2393                                })
 2394                                .ok();
 2395                        });
 2396                    }
 2397                }
 2398                EditorEvent::Edited { .. } => {
 2399                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2400                        .map(|vim_mode| vim_mode.0)
 2401                        .unwrap_or(false);
 2402                    if !vim_mode {
 2403                        let display_map = editor.display_snapshot(cx);
 2404                        let selections = editor.selections.all_adjusted_display(&display_map);
 2405                        let pop_state = editor
 2406                            .change_list
 2407                            .last()
 2408                            .map(|previous| {
 2409                                previous.len() == selections.len()
 2410                                    && previous.iter().enumerate().all(|(ix, p)| {
 2411                                        p.to_display_point(&display_map).row()
 2412                                            == selections[ix].head().row()
 2413                                    })
 2414                            })
 2415                            .unwrap_or(false);
 2416                        let new_positions = selections
 2417                            .into_iter()
 2418                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2419                            .collect();
 2420                        editor
 2421                            .change_list
 2422                            .push_to_change_list(pop_state, new_positions);
 2423                    }
 2424                }
 2425                _ => (),
 2426            },
 2427        ));
 2428
 2429        if let Some(dap_store) = editor
 2430            .project
 2431            .as_ref()
 2432            .map(|project| project.read(cx).dap_store())
 2433        {
 2434            let weak_editor = cx.weak_entity();
 2435
 2436            editor
 2437                ._subscriptions
 2438                .push(
 2439                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2440                        let session_entity = cx.entity();
 2441                        weak_editor
 2442                            .update(cx, |editor, cx| {
 2443                                editor._subscriptions.push(
 2444                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2445                                );
 2446                            })
 2447                            .ok();
 2448                    }),
 2449                );
 2450
 2451            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2452                editor
 2453                    ._subscriptions
 2454                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2455            }
 2456        }
 2457
 2458        // skip adding the initial selection to selection history
 2459        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2460        editor.end_selection(window, cx);
 2461        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2462
 2463        editor.scroll_manager.show_scrollbars(window, cx);
 2464        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2465
 2466        if full_mode {
 2467            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2468            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2469
 2470            if editor.git_blame_inline_enabled {
 2471                editor.start_git_blame_inline(false, window, cx);
 2472            }
 2473
 2474            editor.go_to_active_debug_line(window, cx);
 2475
 2476            editor.minimap =
 2477                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2478            editor.colors = Some(LspColorData::new(cx));
 2479            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2480
 2481            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2482                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2483            }
 2484            editor.update_lsp_data(None, window, cx);
 2485            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2486        }
 2487
 2488        editor
 2489    }
 2490
 2491    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2492        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2493    }
 2494
 2495    pub fn deploy_mouse_context_menu(
 2496        &mut self,
 2497        position: gpui::Point<Pixels>,
 2498        context_menu: Entity<ContextMenu>,
 2499        window: &mut Window,
 2500        cx: &mut Context<Self>,
 2501    ) {
 2502        self.mouse_context_menu = Some(MouseContextMenu::new(
 2503            self,
 2504            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2505            context_menu,
 2506            window,
 2507            cx,
 2508        ));
 2509    }
 2510
 2511    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2512        self.mouse_context_menu
 2513            .as_ref()
 2514            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2515    }
 2516
 2517    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2518        if self
 2519            .selections
 2520            .pending_anchor()
 2521            .is_some_and(|pending_selection| {
 2522                let snapshot = self.buffer().read(cx).snapshot(cx);
 2523                pending_selection.range().includes(range, &snapshot)
 2524            })
 2525        {
 2526            return true;
 2527        }
 2528
 2529        self.selections
 2530            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2531            .into_iter()
 2532            .any(|selection| {
 2533                // This is needed to cover a corner case, if we just check for an existing
 2534                // selection in the fold range, having a cursor at the start of the fold
 2535                // marks it as selected. Non-empty selections don't cause this.
 2536                let length = selection.end - selection.start;
 2537                length > 0
 2538            })
 2539    }
 2540
 2541    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2542        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2543    }
 2544
 2545    fn key_context_internal(
 2546        &self,
 2547        has_active_edit_prediction: bool,
 2548        window: &mut Window,
 2549        cx: &mut App,
 2550    ) -> KeyContext {
 2551        let mut key_context = KeyContext::new_with_defaults();
 2552        key_context.add("Editor");
 2553        let mode = match self.mode {
 2554            EditorMode::SingleLine => "single_line",
 2555            EditorMode::AutoHeight { .. } => "auto_height",
 2556            EditorMode::Minimap { .. } => "minimap",
 2557            EditorMode::Full { .. } => "full",
 2558        };
 2559
 2560        if EditorSettings::jupyter_enabled(cx) {
 2561            key_context.add("jupyter");
 2562        }
 2563
 2564        key_context.set("mode", mode);
 2565        if self.pending_rename.is_some() {
 2566            key_context.add("renaming");
 2567        }
 2568
 2569        if let Some(snippet_stack) = self.snippet_stack.last() {
 2570            key_context.add("in_snippet");
 2571
 2572            if snippet_stack.active_index > 0 {
 2573                key_context.add("has_previous_tabstop");
 2574            }
 2575
 2576            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2577                key_context.add("has_next_tabstop");
 2578            }
 2579        }
 2580
 2581        match self.context_menu.borrow().as_ref() {
 2582            Some(CodeContextMenu::Completions(menu)) => {
 2583                if menu.visible() {
 2584                    key_context.add("menu");
 2585                    key_context.add("showing_completions");
 2586                }
 2587            }
 2588            Some(CodeContextMenu::CodeActions(menu)) => {
 2589                if menu.visible() {
 2590                    key_context.add("menu");
 2591                    key_context.add("showing_code_actions")
 2592                }
 2593            }
 2594            None => {}
 2595        }
 2596
 2597        if self.signature_help_state.has_multiple_signatures() {
 2598            key_context.add("showing_signature_help");
 2599        }
 2600
 2601        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2602        if !self.focus_handle(cx).contains_focused(window, cx)
 2603            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2604        {
 2605            for addon in self.addons.values() {
 2606                addon.extend_key_context(&mut key_context, cx)
 2607            }
 2608        }
 2609
 2610        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2611            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2612                Some(
 2613                    file.full_path(cx)
 2614                        .extension()?
 2615                        .to_string_lossy()
 2616                        .into_owned(),
 2617                )
 2618            }) {
 2619                key_context.set("extension", extension);
 2620            }
 2621        } else {
 2622            key_context.add("multibuffer");
 2623        }
 2624
 2625        if has_active_edit_prediction {
 2626            if self.edit_prediction_in_conflict() {
 2627                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2628            } else {
 2629                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2630                key_context.add("copilot_suggestion");
 2631            }
 2632        }
 2633
 2634        if self.selection_mark_mode {
 2635            key_context.add("selection_mode");
 2636        }
 2637
 2638        let disjoint = self.selections.disjoint_anchors();
 2639        let snapshot = self.snapshot(window, cx);
 2640        let snapshot = snapshot.buffer_snapshot();
 2641        if self.mode == EditorMode::SingleLine
 2642            && let [selection] = disjoint
 2643            && selection.start == selection.end
 2644            && selection.end.to_offset(snapshot) == snapshot.len()
 2645        {
 2646            key_context.add("end_of_input");
 2647        }
 2648
 2649        if self.has_any_expanded_diff_hunks(cx) {
 2650            key_context.add("diffs_expanded");
 2651        }
 2652
 2653        key_context
 2654    }
 2655
 2656    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2657        self.last_bounds.as_ref()
 2658    }
 2659
 2660    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2661        if self.mouse_cursor_hidden {
 2662            self.mouse_cursor_hidden = false;
 2663            cx.notify();
 2664        }
 2665    }
 2666
 2667    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2668        let hide_mouse_cursor = match origin {
 2669            HideMouseCursorOrigin::TypingAction => {
 2670                matches!(
 2671                    self.hide_mouse_mode,
 2672                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2673                )
 2674            }
 2675            HideMouseCursorOrigin::MovementAction => {
 2676                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2677            }
 2678        };
 2679        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2680            self.mouse_cursor_hidden = hide_mouse_cursor;
 2681            cx.notify();
 2682        }
 2683    }
 2684
 2685    pub fn edit_prediction_in_conflict(&self) -> bool {
 2686        if !self.show_edit_predictions_in_menu() {
 2687            return false;
 2688        }
 2689
 2690        let showing_completions = self
 2691            .context_menu
 2692            .borrow()
 2693            .as_ref()
 2694            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2695
 2696        showing_completions
 2697            || self.edit_prediction_requires_modifier()
 2698            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2699            // bindings to insert tab characters.
 2700            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2701    }
 2702
 2703    pub fn accept_edit_prediction_keybind(
 2704        &self,
 2705        accept_partial: bool,
 2706        window: &mut Window,
 2707        cx: &mut App,
 2708    ) -> AcceptEditPredictionBinding {
 2709        let key_context = self.key_context_internal(true, window, cx);
 2710        let in_conflict = self.edit_prediction_in_conflict();
 2711
 2712        let bindings = if accept_partial {
 2713            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2714        } else {
 2715            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2716        };
 2717
 2718        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2719        // just the first one.
 2720        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2721            !in_conflict
 2722                || binding
 2723                    .keystrokes()
 2724                    .first()
 2725                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2726        }))
 2727    }
 2728
 2729    pub fn new_file(
 2730        workspace: &mut Workspace,
 2731        _: &workspace::NewFile,
 2732        window: &mut Window,
 2733        cx: &mut Context<Workspace>,
 2734    ) {
 2735        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2736            "Failed to create buffer",
 2737            window,
 2738            cx,
 2739            |e, _, _| match e.error_code() {
 2740                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2741                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2742                e.error_tag("required").unwrap_or("the latest version")
 2743            )),
 2744                _ => None,
 2745            },
 2746        );
 2747    }
 2748
 2749    pub fn new_in_workspace(
 2750        workspace: &mut Workspace,
 2751        window: &mut Window,
 2752        cx: &mut Context<Workspace>,
 2753    ) -> Task<Result<Entity<Editor>>> {
 2754        let project = workspace.project().clone();
 2755        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2756
 2757        cx.spawn_in(window, async move |workspace, cx| {
 2758            let buffer = create.await?;
 2759            workspace.update_in(cx, |workspace, window, cx| {
 2760                let editor =
 2761                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2762                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2763                editor
 2764            })
 2765        })
 2766    }
 2767
 2768    fn new_file_vertical(
 2769        workspace: &mut Workspace,
 2770        _: &workspace::NewFileSplitVertical,
 2771        window: &mut Window,
 2772        cx: &mut Context<Workspace>,
 2773    ) {
 2774        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2775    }
 2776
 2777    fn new_file_horizontal(
 2778        workspace: &mut Workspace,
 2779        _: &workspace::NewFileSplitHorizontal,
 2780        window: &mut Window,
 2781        cx: &mut Context<Workspace>,
 2782    ) {
 2783        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2784    }
 2785
 2786    fn new_file_split(
 2787        workspace: &mut Workspace,
 2788        action: &workspace::NewFileSplit,
 2789        window: &mut Window,
 2790        cx: &mut Context<Workspace>,
 2791    ) {
 2792        Self::new_file_in_direction(workspace, action.0, window, cx)
 2793    }
 2794
 2795    fn new_file_in_direction(
 2796        workspace: &mut Workspace,
 2797        direction: SplitDirection,
 2798        window: &mut Window,
 2799        cx: &mut Context<Workspace>,
 2800    ) {
 2801        let project = workspace.project().clone();
 2802        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2803
 2804        cx.spawn_in(window, async move |workspace, cx| {
 2805            let buffer = create.await?;
 2806            workspace.update_in(cx, move |workspace, window, cx| {
 2807                workspace.split_item(
 2808                    direction,
 2809                    Box::new(
 2810                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2811                    ),
 2812                    window,
 2813                    cx,
 2814                )
 2815            })?;
 2816            anyhow::Ok(())
 2817        })
 2818        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2819            match e.error_code() {
 2820                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2821                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2822                e.error_tag("required").unwrap_or("the latest version")
 2823            )),
 2824                _ => None,
 2825            }
 2826        });
 2827    }
 2828
 2829    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2830        self.leader_id
 2831    }
 2832
 2833    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2834        &self.buffer
 2835    }
 2836
 2837    pub fn project(&self) -> Option<&Entity<Project>> {
 2838        self.project.as_ref()
 2839    }
 2840
 2841    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2842        self.workspace.as_ref()?.0.upgrade()
 2843    }
 2844
 2845    /// Returns the workspace serialization ID if this editor should be serialized.
 2846    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2847        self.workspace
 2848            .as_ref()
 2849            .filter(|_| self.should_serialize_buffer())
 2850            .and_then(|workspace| workspace.1)
 2851    }
 2852
 2853    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2854        self.buffer().read(cx).title(cx)
 2855    }
 2856
 2857    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2858        let git_blame_gutter_max_author_length = self
 2859            .render_git_blame_gutter(cx)
 2860            .then(|| {
 2861                if let Some(blame) = self.blame.as_ref() {
 2862                    let max_author_length =
 2863                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2864                    Some(max_author_length)
 2865                } else {
 2866                    None
 2867                }
 2868            })
 2869            .flatten();
 2870
 2871        EditorSnapshot {
 2872            mode: self.mode.clone(),
 2873            show_gutter: self.show_gutter,
 2874            show_line_numbers: self.show_line_numbers,
 2875            show_git_diff_gutter: self.show_git_diff_gutter,
 2876            show_code_actions: self.show_code_actions,
 2877            show_runnables: self.show_runnables,
 2878            show_breakpoints: self.show_breakpoints,
 2879            git_blame_gutter_max_author_length,
 2880            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2881            placeholder_display_snapshot: self
 2882                .placeholder_display_map
 2883                .as_ref()
 2884                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2885            scroll_anchor: self.scroll_manager.anchor(),
 2886            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2887            is_focused: self.focus_handle.is_focused(window),
 2888            current_line_highlight: self
 2889                .current_line_highlight
 2890                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2891            gutter_hovered: self.gutter_hovered,
 2892        }
 2893    }
 2894
 2895    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2896        self.buffer.read(cx).language_at(point, cx)
 2897    }
 2898
 2899    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2900        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2901    }
 2902
 2903    pub fn active_excerpt(
 2904        &self,
 2905        cx: &App,
 2906    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2907        self.buffer
 2908            .read(cx)
 2909            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2910    }
 2911
 2912    pub fn mode(&self) -> &EditorMode {
 2913        &self.mode
 2914    }
 2915
 2916    pub fn set_mode(&mut self, mode: EditorMode) {
 2917        self.mode = mode;
 2918    }
 2919
 2920    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2921        self.collaboration_hub.as_deref()
 2922    }
 2923
 2924    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2925        self.collaboration_hub = Some(hub);
 2926    }
 2927
 2928    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2929        self.in_project_search = in_project_search;
 2930    }
 2931
 2932    pub fn set_custom_context_menu(
 2933        &mut self,
 2934        f: impl 'static
 2935        + Fn(
 2936            &mut Self,
 2937            DisplayPoint,
 2938            &mut Window,
 2939            &mut Context<Self>,
 2940        ) -> Option<Entity<ui::ContextMenu>>,
 2941    ) {
 2942        self.custom_context_menu = Some(Box::new(f))
 2943    }
 2944
 2945    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2946        self.completion_provider = provider;
 2947    }
 2948
 2949    #[cfg(any(test, feature = "test-support"))]
 2950    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2951        self.completion_provider.clone()
 2952    }
 2953
 2954    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2955        self.semantics_provider.clone()
 2956    }
 2957
 2958    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2959        self.semantics_provider = provider;
 2960    }
 2961
 2962    pub fn set_edit_prediction_provider<T>(
 2963        &mut self,
 2964        provider: Option<Entity<T>>,
 2965        window: &mut Window,
 2966        cx: &mut Context<Self>,
 2967    ) where
 2968        T: EditPredictionProvider,
 2969    {
 2970        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2971            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2972                if this.focus_handle.is_focused(window) {
 2973                    this.update_visible_edit_prediction(window, cx);
 2974                }
 2975            }),
 2976            provider: Arc::new(provider),
 2977        });
 2978        self.update_edit_prediction_settings(cx);
 2979        self.refresh_edit_prediction(false, false, window, cx);
 2980    }
 2981
 2982    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2983        self.placeholder_display_map
 2984            .as_ref()
 2985            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2986    }
 2987
 2988    pub fn set_placeholder_text(
 2989        &mut self,
 2990        placeholder_text: &str,
 2991        window: &mut Window,
 2992        cx: &mut Context<Self>,
 2993    ) {
 2994        let multibuffer = cx
 2995            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2996
 2997        let style = window.text_style();
 2998
 2999        self.placeholder_display_map = Some(cx.new(|cx| {
 3000            DisplayMap::new(
 3001                multibuffer,
 3002                style.font(),
 3003                style.font_size.to_pixels(window.rem_size()),
 3004                None,
 3005                FILE_HEADER_HEIGHT,
 3006                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3007                Default::default(),
 3008                DiagnosticSeverity::Off,
 3009                cx,
 3010            )
 3011        }));
 3012        cx.notify();
 3013    }
 3014
 3015    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3016        self.cursor_shape = cursor_shape;
 3017
 3018        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3019        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3020
 3021        cx.notify();
 3022    }
 3023
 3024    pub fn set_current_line_highlight(
 3025        &mut self,
 3026        current_line_highlight: Option<CurrentLineHighlight>,
 3027    ) {
 3028        self.current_line_highlight = current_line_highlight;
 3029    }
 3030
 3031    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3032        self.collapse_matches = collapse_matches;
 3033    }
 3034
 3035    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3036        if self.collapse_matches {
 3037            return range.start..range.start;
 3038        }
 3039        range.clone()
 3040    }
 3041
 3042    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3043        self.display_map.read(cx).clip_at_line_ends
 3044    }
 3045
 3046    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3047        if self.display_map.read(cx).clip_at_line_ends != clip {
 3048            self.display_map
 3049                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3050        }
 3051    }
 3052
 3053    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3054        self.input_enabled = input_enabled;
 3055    }
 3056
 3057    pub fn set_edit_predictions_hidden_for_vim_mode(
 3058        &mut self,
 3059        hidden: bool,
 3060        window: &mut Window,
 3061        cx: &mut Context<Self>,
 3062    ) {
 3063        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3064            self.edit_predictions_hidden_for_vim_mode = hidden;
 3065            if hidden {
 3066                self.update_visible_edit_prediction(window, cx);
 3067            } else {
 3068                self.refresh_edit_prediction(true, false, window, cx);
 3069            }
 3070        }
 3071    }
 3072
 3073    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3074        self.menu_edit_predictions_policy = value;
 3075    }
 3076
 3077    pub fn set_autoindent(&mut self, autoindent: bool) {
 3078        if autoindent {
 3079            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3080        } else {
 3081            self.autoindent_mode = None;
 3082        }
 3083    }
 3084
 3085    pub fn read_only(&self, cx: &App) -> bool {
 3086        self.read_only || self.buffer.read(cx).read_only()
 3087    }
 3088
 3089    pub fn set_read_only(&mut self, read_only: bool) {
 3090        self.read_only = read_only;
 3091    }
 3092
 3093    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3094        self.use_autoclose = autoclose;
 3095    }
 3096
 3097    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3098        self.use_auto_surround = auto_surround;
 3099    }
 3100
 3101    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3102        self.auto_replace_emoji_shortcode = auto_replace;
 3103    }
 3104
 3105    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3106        self.buffer_serialization = should_serialize.then(|| {
 3107            BufferSerialization::new(
 3108                ProjectSettings::get_global(cx)
 3109                    .session
 3110                    .restore_unsaved_buffers,
 3111            )
 3112        })
 3113    }
 3114
 3115    fn should_serialize_buffer(&self) -> bool {
 3116        self.buffer_serialization.is_some()
 3117    }
 3118
 3119    pub fn toggle_edit_predictions(
 3120        &mut self,
 3121        _: &ToggleEditPrediction,
 3122        window: &mut Window,
 3123        cx: &mut Context<Self>,
 3124    ) {
 3125        if self.show_edit_predictions_override.is_some() {
 3126            self.set_show_edit_predictions(None, window, cx);
 3127        } else {
 3128            let show_edit_predictions = !self.edit_predictions_enabled();
 3129            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3130        }
 3131    }
 3132
 3133    pub fn set_show_edit_predictions(
 3134        &mut self,
 3135        show_edit_predictions: Option<bool>,
 3136        window: &mut Window,
 3137        cx: &mut Context<Self>,
 3138    ) {
 3139        self.show_edit_predictions_override = show_edit_predictions;
 3140        self.update_edit_prediction_settings(cx);
 3141
 3142        if let Some(false) = show_edit_predictions {
 3143            self.discard_edit_prediction(false, cx);
 3144        } else {
 3145            self.refresh_edit_prediction(false, true, window, cx);
 3146        }
 3147    }
 3148
 3149    fn edit_predictions_disabled_in_scope(
 3150        &self,
 3151        buffer: &Entity<Buffer>,
 3152        buffer_position: language::Anchor,
 3153        cx: &App,
 3154    ) -> bool {
 3155        let snapshot = buffer.read(cx).snapshot();
 3156        let settings = snapshot.settings_at(buffer_position, cx);
 3157
 3158        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3159            return false;
 3160        };
 3161
 3162        scope.override_name().is_some_and(|scope_name| {
 3163            settings
 3164                .edit_predictions_disabled_in
 3165                .iter()
 3166                .any(|s| s == scope_name)
 3167        })
 3168    }
 3169
 3170    pub fn set_use_modal_editing(&mut self, to: bool) {
 3171        self.use_modal_editing = to;
 3172    }
 3173
 3174    pub fn use_modal_editing(&self) -> bool {
 3175        self.use_modal_editing
 3176    }
 3177
 3178    fn selections_did_change(
 3179        &mut self,
 3180        local: bool,
 3181        old_cursor_position: &Anchor,
 3182        effects: SelectionEffects,
 3183        window: &mut Window,
 3184        cx: &mut Context<Self>,
 3185    ) {
 3186        window.invalidate_character_coordinates();
 3187
 3188        // Copy selections to primary selection buffer
 3189        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3190        if local {
 3191            let selections = self
 3192                .selections
 3193                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3194            let buffer_handle = self.buffer.read(cx).read(cx);
 3195
 3196            let mut text = String::new();
 3197            for (index, selection) in selections.iter().enumerate() {
 3198                let text_for_selection = buffer_handle
 3199                    .text_for_range(selection.start..selection.end)
 3200                    .collect::<String>();
 3201
 3202                text.push_str(&text_for_selection);
 3203                if index != selections.len() - 1 {
 3204                    text.push('\n');
 3205                }
 3206            }
 3207
 3208            if !text.is_empty() {
 3209                cx.write_to_primary(ClipboardItem::new_string(text));
 3210            }
 3211        }
 3212
 3213        let selection_anchors = self.selections.disjoint_anchors_arc();
 3214
 3215        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3216            self.buffer.update(cx, |buffer, cx| {
 3217                buffer.set_active_selections(
 3218                    &selection_anchors,
 3219                    self.selections.line_mode(),
 3220                    self.cursor_shape,
 3221                    cx,
 3222                )
 3223            });
 3224        }
 3225        let display_map = self
 3226            .display_map
 3227            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3228        let buffer = display_map.buffer_snapshot();
 3229        if self.selections.count() == 1 {
 3230            self.add_selections_state = None;
 3231        }
 3232        self.select_next_state = None;
 3233        self.select_prev_state = None;
 3234        self.select_syntax_node_history.try_clear();
 3235        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3236        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3237        self.take_rename(false, window, cx);
 3238
 3239        let newest_selection = self.selections.newest_anchor();
 3240        let new_cursor_position = newest_selection.head();
 3241        let selection_start = newest_selection.start;
 3242
 3243        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3244            self.push_to_nav_history(
 3245                *old_cursor_position,
 3246                Some(new_cursor_position.to_point(buffer)),
 3247                false,
 3248                effects.nav_history == Some(true),
 3249                cx,
 3250            );
 3251        }
 3252
 3253        if local {
 3254            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3255                self.register_buffer(buffer_id, cx);
 3256            }
 3257
 3258            let mut context_menu = self.context_menu.borrow_mut();
 3259            let completion_menu = match context_menu.as_ref() {
 3260                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3261                Some(CodeContextMenu::CodeActions(_)) => {
 3262                    *context_menu = None;
 3263                    None
 3264                }
 3265                None => None,
 3266            };
 3267            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3268            drop(context_menu);
 3269
 3270            if effects.completions
 3271                && let Some(completion_position) = completion_position
 3272            {
 3273                let start_offset = selection_start.to_offset(buffer);
 3274                let position_matches = start_offset == completion_position.to_offset(buffer);
 3275                let continue_showing = if position_matches {
 3276                    if self.snippet_stack.is_empty() {
 3277                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3278                            == Some(CharKind::Word)
 3279                    } else {
 3280                        // Snippet choices can be shown even when the cursor is in whitespace.
 3281                        // Dismissing the menu with actions like backspace is handled by
 3282                        // invalidation regions.
 3283                        true
 3284                    }
 3285                } else {
 3286                    false
 3287                };
 3288
 3289                if continue_showing {
 3290                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3291                } else {
 3292                    self.hide_context_menu(window, cx);
 3293                }
 3294            }
 3295
 3296            hide_hover(self, cx);
 3297
 3298            if old_cursor_position.to_display_point(&display_map).row()
 3299                != new_cursor_position.to_display_point(&display_map).row()
 3300            {
 3301                self.available_code_actions.take();
 3302            }
 3303            self.refresh_code_actions(window, cx);
 3304            self.refresh_document_highlights(cx);
 3305            refresh_linked_ranges(self, window, cx);
 3306
 3307            self.refresh_selected_text_highlights(false, window, cx);
 3308            self.refresh_matching_bracket_highlights(window, cx);
 3309            self.update_visible_edit_prediction(window, cx);
 3310            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3311            self.inline_blame_popover.take();
 3312            if self.git_blame_inline_enabled {
 3313                self.start_inline_blame_timer(window, cx);
 3314            }
 3315        }
 3316
 3317        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3318        cx.emit(EditorEvent::SelectionsChanged { local });
 3319
 3320        let selections = &self.selections.disjoint_anchors_arc();
 3321        if selections.len() == 1 {
 3322            cx.emit(SearchEvent::ActiveMatchChanged)
 3323        }
 3324        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3325            let inmemory_selections = selections
 3326                .iter()
 3327                .map(|s| {
 3328                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3329                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3330                })
 3331                .collect();
 3332            self.update_restoration_data(cx, |data| {
 3333                data.selections = inmemory_selections;
 3334            });
 3335
 3336            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3337                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3338            {
 3339                let snapshot = self.buffer().read(cx).snapshot(cx);
 3340                let selections = selections.clone();
 3341                let background_executor = cx.background_executor().clone();
 3342                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3343                self.serialize_selections = cx.background_spawn(async move {
 3344                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3345                    let db_selections = selections
 3346                        .iter()
 3347                        .map(|selection| {
 3348                            (
 3349                                selection.start.to_offset(&snapshot).0,
 3350                                selection.end.to_offset(&snapshot).0,
 3351                            )
 3352                        })
 3353                        .collect();
 3354
 3355                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3356                        .await
 3357                        .with_context(|| {
 3358                            format!(
 3359                                "persisting editor selections for editor {editor_id}, \
 3360                                workspace {workspace_id:?}"
 3361                            )
 3362                        })
 3363                        .log_err();
 3364                });
 3365            }
 3366        }
 3367
 3368        cx.notify();
 3369    }
 3370
 3371    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3372        use text::ToOffset as _;
 3373        use text::ToPoint as _;
 3374
 3375        if self.mode.is_minimap()
 3376            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3377        {
 3378            return;
 3379        }
 3380
 3381        if !self.buffer().read(cx).is_singleton() {
 3382            return;
 3383        }
 3384
 3385        let display_snapshot = self
 3386            .display_map
 3387            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3388        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3389            return;
 3390        };
 3391        let inmemory_folds = display_snapshot
 3392            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3393            .map(|fold| {
 3394                fold.range.start.text_anchor.to_point(&snapshot)
 3395                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3396            })
 3397            .collect();
 3398        self.update_restoration_data(cx, |data| {
 3399            data.folds = inmemory_folds;
 3400        });
 3401
 3402        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3403            return;
 3404        };
 3405        let background_executor = cx.background_executor().clone();
 3406        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3407        let db_folds = display_snapshot
 3408            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3409            .map(|fold| {
 3410                (
 3411                    fold.range.start.text_anchor.to_offset(&snapshot),
 3412                    fold.range.end.text_anchor.to_offset(&snapshot),
 3413                )
 3414            })
 3415            .collect();
 3416        self.serialize_folds = cx.background_spawn(async move {
 3417            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3418            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3419                .await
 3420                .with_context(|| {
 3421                    format!(
 3422                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3423                    )
 3424                })
 3425                .log_err();
 3426        });
 3427    }
 3428
 3429    pub fn sync_selections(
 3430        &mut self,
 3431        other: Entity<Editor>,
 3432        cx: &mut Context<Self>,
 3433    ) -> gpui::Subscription {
 3434        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3435        if !other_selections.is_empty() {
 3436            self.selections
 3437                .change_with(&self.display_snapshot(cx), |selections| {
 3438                    selections.select_anchors(other_selections);
 3439                });
 3440        }
 3441
 3442        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3443            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3444                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3445                if other_selections.is_empty() {
 3446                    return;
 3447                }
 3448                let snapshot = this.display_snapshot(cx);
 3449                this.selections.change_with(&snapshot, |selections| {
 3450                    selections.select_anchors(other_selections);
 3451                });
 3452            }
 3453        });
 3454
 3455        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3456            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3457                let these_selections = this.selections.disjoint_anchors().to_vec();
 3458                if these_selections.is_empty() {
 3459                    return;
 3460                }
 3461                other.update(cx, |other_editor, cx| {
 3462                    let snapshot = other_editor.display_snapshot(cx);
 3463                    other_editor
 3464                        .selections
 3465                        .change_with(&snapshot, |selections| {
 3466                            selections.select_anchors(these_selections);
 3467                        })
 3468                });
 3469            }
 3470        });
 3471
 3472        Subscription::join(other_subscription, this_subscription)
 3473    }
 3474
 3475    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3476        if self.buffer().read(cx).is_singleton() {
 3477            return;
 3478        }
 3479        let snapshot = self.buffer.read(cx).snapshot(cx);
 3480        let buffer_ids: HashSet<BufferId> = self
 3481            .selections
 3482            .disjoint_anchor_ranges()
 3483            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3484            .collect();
 3485        for buffer_id in buffer_ids {
 3486            self.unfold_buffer(buffer_id, cx);
 3487        }
 3488    }
 3489
 3490    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3491    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3492    /// effects of selection change occur at the end of the transaction.
 3493    pub fn change_selections<R>(
 3494        &mut self,
 3495        effects: SelectionEffects,
 3496        window: &mut Window,
 3497        cx: &mut Context<Self>,
 3498        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3499    ) -> R {
 3500        let snapshot = self.display_snapshot(cx);
 3501        if let Some(state) = &mut self.deferred_selection_effects_state {
 3502            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3503            state.effects.completions = effects.completions;
 3504            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3505            let (changed, result) = self.selections.change_with(&snapshot, change);
 3506            state.changed |= changed;
 3507            return result;
 3508        }
 3509        let mut state = DeferredSelectionEffectsState {
 3510            changed: false,
 3511            effects,
 3512            old_cursor_position: self.selections.newest_anchor().head(),
 3513            history_entry: SelectionHistoryEntry {
 3514                selections: self.selections.disjoint_anchors_arc(),
 3515                select_next_state: self.select_next_state.clone(),
 3516                select_prev_state: self.select_prev_state.clone(),
 3517                add_selections_state: self.add_selections_state.clone(),
 3518            },
 3519        };
 3520        let (changed, result) = self.selections.change_with(&snapshot, change);
 3521        state.changed = state.changed || changed;
 3522        if self.defer_selection_effects {
 3523            self.deferred_selection_effects_state = Some(state);
 3524        } else {
 3525            self.apply_selection_effects(state, window, cx);
 3526        }
 3527        result
 3528    }
 3529
 3530    /// Defers the effects of selection change, so that the effects of multiple calls to
 3531    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3532    /// to selection history and the state of popovers based on selection position aren't
 3533    /// erroneously updated.
 3534    pub fn with_selection_effects_deferred<R>(
 3535        &mut self,
 3536        window: &mut Window,
 3537        cx: &mut Context<Self>,
 3538        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3539    ) -> R {
 3540        let already_deferred = self.defer_selection_effects;
 3541        self.defer_selection_effects = true;
 3542        let result = update(self, window, cx);
 3543        if !already_deferred {
 3544            self.defer_selection_effects = false;
 3545            if let Some(state) = self.deferred_selection_effects_state.take() {
 3546                self.apply_selection_effects(state, window, cx);
 3547            }
 3548        }
 3549        result
 3550    }
 3551
 3552    fn apply_selection_effects(
 3553        &mut self,
 3554        state: DeferredSelectionEffectsState,
 3555        window: &mut Window,
 3556        cx: &mut Context<Self>,
 3557    ) {
 3558        if state.changed {
 3559            self.selection_history.push(state.history_entry);
 3560
 3561            if let Some(autoscroll) = state.effects.scroll {
 3562                self.request_autoscroll(autoscroll, cx);
 3563            }
 3564
 3565            let old_cursor_position = &state.old_cursor_position;
 3566
 3567            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3568
 3569            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3570                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3571            }
 3572        }
 3573    }
 3574
 3575    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3576    where
 3577        I: IntoIterator<Item = (Range<S>, T)>,
 3578        S: ToOffset,
 3579        T: Into<Arc<str>>,
 3580    {
 3581        if self.read_only(cx) {
 3582            return;
 3583        }
 3584
 3585        self.buffer
 3586            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3587    }
 3588
 3589    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3590    where
 3591        I: IntoIterator<Item = (Range<S>, T)>,
 3592        S: ToOffset,
 3593        T: Into<Arc<str>>,
 3594    {
 3595        if self.read_only(cx) {
 3596            return;
 3597        }
 3598
 3599        self.buffer.update(cx, |buffer, cx| {
 3600            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3601        });
 3602    }
 3603
 3604    pub fn edit_with_block_indent<I, S, T>(
 3605        &mut self,
 3606        edits: I,
 3607        original_indent_columns: Vec<Option<u32>>,
 3608        cx: &mut Context<Self>,
 3609    ) where
 3610        I: IntoIterator<Item = (Range<S>, T)>,
 3611        S: ToOffset,
 3612        T: Into<Arc<str>>,
 3613    {
 3614        if self.read_only(cx) {
 3615            return;
 3616        }
 3617
 3618        self.buffer.update(cx, |buffer, cx| {
 3619            buffer.edit(
 3620                edits,
 3621                Some(AutoindentMode::Block {
 3622                    original_indent_columns,
 3623                }),
 3624                cx,
 3625            )
 3626        });
 3627    }
 3628
 3629    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3630        self.hide_context_menu(window, cx);
 3631
 3632        match phase {
 3633            SelectPhase::Begin {
 3634                position,
 3635                add,
 3636                click_count,
 3637            } => self.begin_selection(position, add, click_count, window, cx),
 3638            SelectPhase::BeginColumnar {
 3639                position,
 3640                goal_column,
 3641                reset,
 3642                mode,
 3643            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3644            SelectPhase::Extend {
 3645                position,
 3646                click_count,
 3647            } => self.extend_selection(position, click_count, window, cx),
 3648            SelectPhase::Update {
 3649                position,
 3650                goal_column,
 3651                scroll_delta,
 3652            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3653            SelectPhase::End => self.end_selection(window, cx),
 3654        }
 3655    }
 3656
 3657    fn extend_selection(
 3658        &mut self,
 3659        position: DisplayPoint,
 3660        click_count: usize,
 3661        window: &mut Window,
 3662        cx: &mut Context<Self>,
 3663    ) {
 3664        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3665        let tail = self
 3666            .selections
 3667            .newest::<MultiBufferOffset>(&display_map)
 3668            .tail();
 3669        let click_count = click_count.max(match self.selections.select_mode() {
 3670            SelectMode::Character => 1,
 3671            SelectMode::Word(_) => 2,
 3672            SelectMode::Line(_) => 3,
 3673            SelectMode::All => 4,
 3674        });
 3675        self.begin_selection(position, false, click_count, window, cx);
 3676
 3677        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3678
 3679        let current_selection = match self.selections.select_mode() {
 3680            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3681            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3682        };
 3683
 3684        let mut pending_selection = self
 3685            .selections
 3686            .pending_anchor()
 3687            .cloned()
 3688            .expect("extend_selection not called with pending selection");
 3689
 3690        if pending_selection
 3691            .start
 3692            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3693            == Ordering::Greater
 3694        {
 3695            pending_selection.start = current_selection.start;
 3696        }
 3697        if pending_selection
 3698            .end
 3699            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3700            == Ordering::Less
 3701        {
 3702            pending_selection.end = current_selection.end;
 3703            pending_selection.reversed = true;
 3704        }
 3705
 3706        let mut pending_mode = self.selections.pending_mode().unwrap();
 3707        match &mut pending_mode {
 3708            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3709            _ => {}
 3710        }
 3711
 3712        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3713            SelectionEffects::scroll(Autoscroll::fit())
 3714        } else {
 3715            SelectionEffects::no_scroll()
 3716        };
 3717
 3718        self.change_selections(effects, window, cx, |s| {
 3719            s.set_pending(pending_selection.clone(), pending_mode);
 3720            s.set_is_extending(true);
 3721        });
 3722    }
 3723
 3724    fn begin_selection(
 3725        &mut self,
 3726        position: DisplayPoint,
 3727        add: bool,
 3728        click_count: usize,
 3729        window: &mut Window,
 3730        cx: &mut Context<Self>,
 3731    ) {
 3732        if !self.focus_handle.is_focused(window) {
 3733            self.last_focused_descendant = None;
 3734            window.focus(&self.focus_handle);
 3735        }
 3736
 3737        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3738        let buffer = display_map.buffer_snapshot();
 3739        let position = display_map.clip_point(position, Bias::Left);
 3740
 3741        let start;
 3742        let end;
 3743        let mode;
 3744        let mut auto_scroll;
 3745        match click_count {
 3746            1 => {
 3747                start = buffer.anchor_before(position.to_point(&display_map));
 3748                end = start;
 3749                mode = SelectMode::Character;
 3750                auto_scroll = true;
 3751            }
 3752            2 => {
 3753                let position = display_map
 3754                    .clip_point(position, Bias::Left)
 3755                    .to_offset(&display_map, Bias::Left);
 3756                let (range, _) = buffer.surrounding_word(position, None);
 3757                start = buffer.anchor_before(range.start);
 3758                end = buffer.anchor_before(range.end);
 3759                mode = SelectMode::Word(start..end);
 3760                auto_scroll = true;
 3761            }
 3762            3 => {
 3763                let position = display_map
 3764                    .clip_point(position, Bias::Left)
 3765                    .to_point(&display_map);
 3766                let line_start = display_map.prev_line_boundary(position).0;
 3767                let next_line_start = buffer.clip_point(
 3768                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3769                    Bias::Left,
 3770                );
 3771                start = buffer.anchor_before(line_start);
 3772                end = buffer.anchor_before(next_line_start);
 3773                mode = SelectMode::Line(start..end);
 3774                auto_scroll = true;
 3775            }
 3776            _ => {
 3777                start = buffer.anchor_before(MultiBufferOffset(0));
 3778                end = buffer.anchor_before(buffer.len());
 3779                mode = SelectMode::All;
 3780                auto_scroll = false;
 3781            }
 3782        }
 3783        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3784
 3785        let point_to_delete: Option<usize> = {
 3786            let selected_points: Vec<Selection<Point>> =
 3787                self.selections.disjoint_in_range(start..end, &display_map);
 3788
 3789            if !add || click_count > 1 {
 3790                None
 3791            } else if !selected_points.is_empty() {
 3792                Some(selected_points[0].id)
 3793            } else {
 3794                let clicked_point_already_selected =
 3795                    self.selections.disjoint_anchors().iter().find(|selection| {
 3796                        selection.start.to_point(buffer) == start.to_point(buffer)
 3797                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3798                    });
 3799
 3800                clicked_point_already_selected.map(|selection| selection.id)
 3801            }
 3802        };
 3803
 3804        let selections_count = self.selections.count();
 3805        let effects = if auto_scroll {
 3806            SelectionEffects::default()
 3807        } else {
 3808            SelectionEffects::no_scroll()
 3809        };
 3810
 3811        self.change_selections(effects, window, cx, |s| {
 3812            if let Some(point_to_delete) = point_to_delete {
 3813                s.delete(point_to_delete);
 3814
 3815                if selections_count == 1 {
 3816                    s.set_pending_anchor_range(start..end, mode);
 3817                }
 3818            } else {
 3819                if !add {
 3820                    s.clear_disjoint();
 3821                }
 3822
 3823                s.set_pending_anchor_range(start..end, mode);
 3824            }
 3825        });
 3826    }
 3827
 3828    fn begin_columnar_selection(
 3829        &mut self,
 3830        position: DisplayPoint,
 3831        goal_column: u32,
 3832        reset: bool,
 3833        mode: ColumnarMode,
 3834        window: &mut Window,
 3835        cx: &mut Context<Self>,
 3836    ) {
 3837        if !self.focus_handle.is_focused(window) {
 3838            self.last_focused_descendant = None;
 3839            window.focus(&self.focus_handle);
 3840        }
 3841
 3842        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3843
 3844        if reset {
 3845            let pointer_position = display_map
 3846                .buffer_snapshot()
 3847                .anchor_before(position.to_point(&display_map));
 3848
 3849            self.change_selections(
 3850                SelectionEffects::scroll(Autoscroll::newest()),
 3851                window,
 3852                cx,
 3853                |s| {
 3854                    s.clear_disjoint();
 3855                    s.set_pending_anchor_range(
 3856                        pointer_position..pointer_position,
 3857                        SelectMode::Character,
 3858                    );
 3859                },
 3860            );
 3861        };
 3862
 3863        let tail = self.selections.newest::<Point>(&display_map).tail();
 3864        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3865        self.columnar_selection_state = match mode {
 3866            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3867                selection_tail: selection_anchor,
 3868                display_point: if reset {
 3869                    if position.column() != goal_column {
 3870                        Some(DisplayPoint::new(position.row(), goal_column))
 3871                    } else {
 3872                        None
 3873                    }
 3874                } else {
 3875                    None
 3876                },
 3877            }),
 3878            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3879                selection_tail: selection_anchor,
 3880            }),
 3881        };
 3882
 3883        if !reset {
 3884            self.select_columns(position, goal_column, &display_map, window, cx);
 3885        }
 3886    }
 3887
 3888    fn update_selection(
 3889        &mut self,
 3890        position: DisplayPoint,
 3891        goal_column: u32,
 3892        scroll_delta: gpui::Point<f32>,
 3893        window: &mut Window,
 3894        cx: &mut Context<Self>,
 3895    ) {
 3896        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3897
 3898        if self.columnar_selection_state.is_some() {
 3899            self.select_columns(position, goal_column, &display_map, window, cx);
 3900        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3901            let buffer = display_map.buffer_snapshot();
 3902            let head;
 3903            let tail;
 3904            let mode = self.selections.pending_mode().unwrap();
 3905            match &mode {
 3906                SelectMode::Character => {
 3907                    head = position.to_point(&display_map);
 3908                    tail = pending.tail().to_point(buffer);
 3909                }
 3910                SelectMode::Word(original_range) => {
 3911                    let offset = display_map
 3912                        .clip_point(position, Bias::Left)
 3913                        .to_offset(&display_map, Bias::Left);
 3914                    let original_range = original_range.to_offset(buffer);
 3915
 3916                    let head_offset = if buffer.is_inside_word(offset, None)
 3917                        || original_range.contains(&offset)
 3918                    {
 3919                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3920                        if word_range.start < original_range.start {
 3921                            word_range.start
 3922                        } else {
 3923                            word_range.end
 3924                        }
 3925                    } else {
 3926                        offset
 3927                    };
 3928
 3929                    head = head_offset.to_point(buffer);
 3930                    if head_offset <= original_range.start {
 3931                        tail = original_range.end.to_point(buffer);
 3932                    } else {
 3933                        tail = original_range.start.to_point(buffer);
 3934                    }
 3935                }
 3936                SelectMode::Line(original_range) => {
 3937                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3938
 3939                    let position = display_map
 3940                        .clip_point(position, Bias::Left)
 3941                        .to_point(&display_map);
 3942                    let line_start = display_map.prev_line_boundary(position).0;
 3943                    let next_line_start = buffer.clip_point(
 3944                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3945                        Bias::Left,
 3946                    );
 3947
 3948                    if line_start < original_range.start {
 3949                        head = line_start
 3950                    } else {
 3951                        head = next_line_start
 3952                    }
 3953
 3954                    if head <= original_range.start {
 3955                        tail = original_range.end;
 3956                    } else {
 3957                        tail = original_range.start;
 3958                    }
 3959                }
 3960                SelectMode::All => {
 3961                    return;
 3962                }
 3963            };
 3964
 3965            if head < tail {
 3966                pending.start = buffer.anchor_before(head);
 3967                pending.end = buffer.anchor_before(tail);
 3968                pending.reversed = true;
 3969            } else {
 3970                pending.start = buffer.anchor_before(tail);
 3971                pending.end = buffer.anchor_before(head);
 3972                pending.reversed = false;
 3973            }
 3974
 3975            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3976                s.set_pending(pending.clone(), mode);
 3977            });
 3978        } else {
 3979            log::error!("update_selection dispatched with no pending selection");
 3980            return;
 3981        }
 3982
 3983        self.apply_scroll_delta(scroll_delta, window, cx);
 3984        cx.notify();
 3985    }
 3986
 3987    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3988        self.columnar_selection_state.take();
 3989        if let Some(pending_mode) = self.selections.pending_mode() {
 3990            let selections = self
 3991                .selections
 3992                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3993            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3994                s.select(selections);
 3995                s.clear_pending();
 3996                if s.is_extending() {
 3997                    s.set_is_extending(false);
 3998                } else {
 3999                    s.set_select_mode(pending_mode);
 4000                }
 4001            });
 4002        }
 4003    }
 4004
 4005    fn select_columns(
 4006        &mut self,
 4007        head: DisplayPoint,
 4008        goal_column: u32,
 4009        display_map: &DisplaySnapshot,
 4010        window: &mut Window,
 4011        cx: &mut Context<Self>,
 4012    ) {
 4013        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4014            return;
 4015        };
 4016
 4017        let tail = match columnar_state {
 4018            ColumnarSelectionState::FromMouse {
 4019                selection_tail,
 4020                display_point,
 4021            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4022            ColumnarSelectionState::FromSelection { selection_tail } => {
 4023                selection_tail.to_display_point(display_map)
 4024            }
 4025        };
 4026
 4027        let start_row = cmp::min(tail.row(), head.row());
 4028        let end_row = cmp::max(tail.row(), head.row());
 4029        let start_column = cmp::min(tail.column(), goal_column);
 4030        let end_column = cmp::max(tail.column(), goal_column);
 4031        let reversed = start_column < tail.column();
 4032
 4033        let selection_ranges = (start_row.0..=end_row.0)
 4034            .map(DisplayRow)
 4035            .filter_map(|row| {
 4036                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4037                    || start_column <= display_map.line_len(row))
 4038                    && !display_map.is_block_line(row)
 4039                {
 4040                    let start = display_map
 4041                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4042                        .to_point(display_map);
 4043                    let end = display_map
 4044                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4045                        .to_point(display_map);
 4046                    if reversed {
 4047                        Some(end..start)
 4048                    } else {
 4049                        Some(start..end)
 4050                    }
 4051                } else {
 4052                    None
 4053                }
 4054            })
 4055            .collect::<Vec<_>>();
 4056        if selection_ranges.is_empty() {
 4057            return;
 4058        }
 4059
 4060        let ranges = match columnar_state {
 4061            ColumnarSelectionState::FromMouse { .. } => {
 4062                let mut non_empty_ranges = selection_ranges
 4063                    .iter()
 4064                    .filter(|selection_range| selection_range.start != selection_range.end)
 4065                    .peekable();
 4066                if non_empty_ranges.peek().is_some() {
 4067                    non_empty_ranges.cloned().collect()
 4068                } else {
 4069                    selection_ranges
 4070                }
 4071            }
 4072            _ => selection_ranges,
 4073        };
 4074
 4075        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4076            s.select_ranges(ranges);
 4077        });
 4078        cx.notify();
 4079    }
 4080
 4081    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4082        self.selections
 4083            .all_adjusted(snapshot)
 4084            .iter()
 4085            .any(|selection| !selection.is_empty())
 4086    }
 4087
 4088    pub fn has_pending_nonempty_selection(&self) -> bool {
 4089        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4090            Some(Selection { start, end, .. }) => start != end,
 4091            None => false,
 4092        };
 4093
 4094        pending_nonempty_selection
 4095            || (self.columnar_selection_state.is_some()
 4096                && self.selections.disjoint_anchors().len() > 1)
 4097    }
 4098
 4099    pub fn has_pending_selection(&self) -> bool {
 4100        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4101    }
 4102
 4103    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4104        self.selection_mark_mode = false;
 4105        self.selection_drag_state = SelectionDragState::None;
 4106
 4107        if self.dismiss_menus_and_popups(true, window, cx) {
 4108            cx.notify();
 4109            return;
 4110        }
 4111        if self.clear_expanded_diff_hunks(cx) {
 4112            cx.notify();
 4113            return;
 4114        }
 4115        if self.show_git_blame_gutter {
 4116            self.show_git_blame_gutter = false;
 4117            cx.notify();
 4118            return;
 4119        }
 4120
 4121        if self.mode.is_full()
 4122            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4123        {
 4124            cx.notify();
 4125            return;
 4126        }
 4127
 4128        cx.propagate();
 4129    }
 4130
 4131    pub fn dismiss_menus_and_popups(
 4132        &mut self,
 4133        is_user_requested: bool,
 4134        window: &mut Window,
 4135        cx: &mut Context<Self>,
 4136    ) -> bool {
 4137        let mut dismissed = false;
 4138
 4139        dismissed |= self.take_rename(false, window, cx).is_some();
 4140        dismissed |= self.hide_blame_popover(true, cx);
 4141        dismissed |= hide_hover(self, cx);
 4142        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4143        dismissed |= self.hide_context_menu(window, cx).is_some();
 4144        dismissed |= self.mouse_context_menu.take().is_some();
 4145        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4146        dismissed |= self.snippet_stack.pop().is_some();
 4147
 4148        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4149            self.dismiss_diagnostics(cx);
 4150            dismissed = true;
 4151        }
 4152
 4153        dismissed
 4154    }
 4155
 4156    fn linked_editing_ranges_for(
 4157        &self,
 4158        selection: Range<text::Anchor>,
 4159        cx: &App,
 4160    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4161        if self.linked_edit_ranges.is_empty() {
 4162            return None;
 4163        }
 4164        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4165            selection.end.buffer_id.and_then(|end_buffer_id| {
 4166                if selection.start.buffer_id != Some(end_buffer_id) {
 4167                    return None;
 4168                }
 4169                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4170                let snapshot = buffer.read(cx).snapshot();
 4171                self.linked_edit_ranges
 4172                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4173                    .map(|ranges| (ranges, snapshot, buffer))
 4174            })?;
 4175        use text::ToOffset as TO;
 4176        // find offset from the start of current range to current cursor position
 4177        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4178
 4179        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4180        let start_difference = start_offset - start_byte_offset;
 4181        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4182        let end_difference = end_offset - start_byte_offset;
 4183        // Current range has associated linked ranges.
 4184        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4185        for range in linked_ranges.iter() {
 4186            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4187            let end_offset = start_offset + end_difference;
 4188            let start_offset = start_offset + start_difference;
 4189            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4190                continue;
 4191            }
 4192            if self.selections.disjoint_anchor_ranges().any(|s| {
 4193                if s.start.buffer_id != selection.start.buffer_id
 4194                    || s.end.buffer_id != selection.end.buffer_id
 4195                {
 4196                    return false;
 4197                }
 4198                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4199                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4200            }) {
 4201                continue;
 4202            }
 4203            let start = buffer_snapshot.anchor_after(start_offset);
 4204            let end = buffer_snapshot.anchor_after(end_offset);
 4205            linked_edits
 4206                .entry(buffer.clone())
 4207                .or_default()
 4208                .push(start..end);
 4209        }
 4210        Some(linked_edits)
 4211    }
 4212
 4213    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4214        let text: Arc<str> = text.into();
 4215
 4216        if self.read_only(cx) {
 4217            return;
 4218        }
 4219
 4220        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4221
 4222        self.unfold_buffers_with_selections(cx);
 4223
 4224        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4225        let mut bracket_inserted = false;
 4226        let mut edits = Vec::new();
 4227        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4228        let mut new_selections = Vec::with_capacity(selections.len());
 4229        let mut new_autoclose_regions = Vec::new();
 4230        let snapshot = self.buffer.read(cx).read(cx);
 4231        let mut clear_linked_edit_ranges = false;
 4232
 4233        for (selection, autoclose_region) in
 4234            self.selections_with_autoclose_regions(selections, &snapshot)
 4235        {
 4236            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4237                // Determine if the inserted text matches the opening or closing
 4238                // bracket of any of this language's bracket pairs.
 4239                let mut bracket_pair = None;
 4240                let mut is_bracket_pair_start = false;
 4241                let mut is_bracket_pair_end = false;
 4242                if !text.is_empty() {
 4243                    let mut bracket_pair_matching_end = None;
 4244                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4245                    //  and they are removing the character that triggered IME popup.
 4246                    for (pair, enabled) in scope.brackets() {
 4247                        if !pair.close && !pair.surround {
 4248                            continue;
 4249                        }
 4250
 4251                        if enabled && pair.start.ends_with(text.as_ref()) {
 4252                            let prefix_len = pair.start.len() - text.len();
 4253                            let preceding_text_matches_prefix = prefix_len == 0
 4254                                || (selection.start.column >= (prefix_len as u32)
 4255                                    && snapshot.contains_str_at(
 4256                                        Point::new(
 4257                                            selection.start.row,
 4258                                            selection.start.column - (prefix_len as u32),
 4259                                        ),
 4260                                        &pair.start[..prefix_len],
 4261                                    ));
 4262                            if preceding_text_matches_prefix {
 4263                                bracket_pair = Some(pair.clone());
 4264                                is_bracket_pair_start = true;
 4265                                break;
 4266                            }
 4267                        }
 4268                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4269                        {
 4270                            // take first bracket pair matching end, but don't break in case a later bracket
 4271                            // pair matches start
 4272                            bracket_pair_matching_end = Some(pair.clone());
 4273                        }
 4274                    }
 4275                    if let Some(end) = bracket_pair_matching_end
 4276                        && bracket_pair.is_none()
 4277                    {
 4278                        bracket_pair = Some(end);
 4279                        is_bracket_pair_end = true;
 4280                    }
 4281                }
 4282
 4283                if let Some(bracket_pair) = bracket_pair {
 4284                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4285                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4286                    let auto_surround =
 4287                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4288                    if selection.is_empty() {
 4289                        if is_bracket_pair_start {
 4290                            // If the inserted text is a suffix of an opening bracket and the
 4291                            // selection is preceded by the rest of the opening bracket, then
 4292                            // insert the closing bracket.
 4293                            let following_text_allows_autoclose = snapshot
 4294                                .chars_at(selection.start)
 4295                                .next()
 4296                                .is_none_or(|c| scope.should_autoclose_before(c));
 4297
 4298                            let preceding_text_allows_autoclose = selection.start.column == 0
 4299                                || snapshot
 4300                                    .reversed_chars_at(selection.start)
 4301                                    .next()
 4302                                    .is_none_or(|c| {
 4303                                        bracket_pair.start != bracket_pair.end
 4304                                            || !snapshot
 4305                                                .char_classifier_at(selection.start)
 4306                                                .is_word(c)
 4307                                    });
 4308
 4309                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4310                                && bracket_pair.start.len() == 1
 4311                            {
 4312                                let target = bracket_pair.start.chars().next().unwrap();
 4313                                let current_line_count = snapshot
 4314                                    .reversed_chars_at(selection.start)
 4315                                    .take_while(|&c| c != '\n')
 4316                                    .filter(|&c| c == target)
 4317                                    .count();
 4318                                current_line_count % 2 == 1
 4319                            } else {
 4320                                false
 4321                            };
 4322
 4323                            if autoclose
 4324                                && bracket_pair.close
 4325                                && following_text_allows_autoclose
 4326                                && preceding_text_allows_autoclose
 4327                                && !is_closing_quote
 4328                            {
 4329                                let anchor = snapshot.anchor_before(selection.end);
 4330                                new_selections.push((selection.map(|_| anchor), text.len()));
 4331                                new_autoclose_regions.push((
 4332                                    anchor,
 4333                                    text.len(),
 4334                                    selection.id,
 4335                                    bracket_pair.clone(),
 4336                                ));
 4337                                edits.push((
 4338                                    selection.range(),
 4339                                    format!("{}{}", text, bracket_pair.end).into(),
 4340                                ));
 4341                                bracket_inserted = true;
 4342                                continue;
 4343                            }
 4344                        }
 4345
 4346                        if let Some(region) = autoclose_region {
 4347                            // If the selection is followed by an auto-inserted closing bracket,
 4348                            // then don't insert that closing bracket again; just move the selection
 4349                            // past the closing bracket.
 4350                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4351                                && text.as_ref() == region.pair.end.as_str()
 4352                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4353                            if should_skip {
 4354                                let anchor = snapshot.anchor_after(selection.end);
 4355                                new_selections
 4356                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4357                                continue;
 4358                            }
 4359                        }
 4360
 4361                        let always_treat_brackets_as_autoclosed = snapshot
 4362                            .language_settings_at(selection.start, cx)
 4363                            .always_treat_brackets_as_autoclosed;
 4364                        if always_treat_brackets_as_autoclosed
 4365                            && is_bracket_pair_end
 4366                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4367                        {
 4368                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4369                            // and the inserted text is a closing bracket and the selection is followed
 4370                            // by the closing bracket then move the selection past the closing bracket.
 4371                            let anchor = snapshot.anchor_after(selection.end);
 4372                            new_selections.push((selection.map(|_| anchor), text.len()));
 4373                            continue;
 4374                        }
 4375                    }
 4376                    // If an opening bracket is 1 character long and is typed while
 4377                    // text is selected, then surround that text with the bracket pair.
 4378                    else if auto_surround
 4379                        && bracket_pair.surround
 4380                        && is_bracket_pair_start
 4381                        && bracket_pair.start.chars().count() == 1
 4382                    {
 4383                        edits.push((selection.start..selection.start, text.clone()));
 4384                        edits.push((
 4385                            selection.end..selection.end,
 4386                            bracket_pair.end.as_str().into(),
 4387                        ));
 4388                        bracket_inserted = true;
 4389                        new_selections.push((
 4390                            Selection {
 4391                                id: selection.id,
 4392                                start: snapshot.anchor_after(selection.start),
 4393                                end: snapshot.anchor_before(selection.end),
 4394                                reversed: selection.reversed,
 4395                                goal: selection.goal,
 4396                            },
 4397                            0,
 4398                        ));
 4399                        continue;
 4400                    }
 4401                }
 4402            }
 4403
 4404            if self.auto_replace_emoji_shortcode
 4405                && selection.is_empty()
 4406                && text.as_ref().ends_with(':')
 4407                && let Some(possible_emoji_short_code) =
 4408                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4409                && !possible_emoji_short_code.is_empty()
 4410                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4411            {
 4412                let emoji_shortcode_start = Point::new(
 4413                    selection.start.row,
 4414                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4415                );
 4416
 4417                // Remove shortcode from buffer
 4418                edits.push((
 4419                    emoji_shortcode_start..selection.start,
 4420                    "".to_string().into(),
 4421                ));
 4422                new_selections.push((
 4423                    Selection {
 4424                        id: selection.id,
 4425                        start: snapshot.anchor_after(emoji_shortcode_start),
 4426                        end: snapshot.anchor_before(selection.start),
 4427                        reversed: selection.reversed,
 4428                        goal: selection.goal,
 4429                    },
 4430                    0,
 4431                ));
 4432
 4433                // Insert emoji
 4434                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4435                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4436                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4437
 4438                continue;
 4439            }
 4440
 4441            // If not handling any auto-close operation, then just replace the selected
 4442            // text with the given input and move the selection to the end of the
 4443            // newly inserted text.
 4444            let anchor = snapshot.anchor_after(selection.end);
 4445            if !self.linked_edit_ranges.is_empty() {
 4446                let start_anchor = snapshot.anchor_before(selection.start);
 4447
 4448                let is_word_char = text.chars().next().is_none_or(|char| {
 4449                    let classifier = snapshot
 4450                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4451                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4452                    classifier.is_word(char)
 4453                });
 4454
 4455                if is_word_char {
 4456                    if let Some(ranges) = self
 4457                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4458                    {
 4459                        for (buffer, edits) in ranges {
 4460                            linked_edits
 4461                                .entry(buffer.clone())
 4462                                .or_default()
 4463                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4464                        }
 4465                    }
 4466                } else {
 4467                    clear_linked_edit_ranges = true;
 4468                }
 4469            }
 4470
 4471            new_selections.push((selection.map(|_| anchor), 0));
 4472            edits.push((selection.start..selection.end, text.clone()));
 4473        }
 4474
 4475        drop(snapshot);
 4476
 4477        self.transact(window, cx, |this, window, cx| {
 4478            if clear_linked_edit_ranges {
 4479                this.linked_edit_ranges.clear();
 4480            }
 4481            let initial_buffer_versions =
 4482                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4483
 4484            this.buffer.update(cx, |buffer, cx| {
 4485                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4486            });
 4487            for (buffer, edits) in linked_edits {
 4488                buffer.update(cx, |buffer, cx| {
 4489                    let snapshot = buffer.snapshot();
 4490                    let edits = edits
 4491                        .into_iter()
 4492                        .map(|(range, text)| {
 4493                            use text::ToPoint as TP;
 4494                            let end_point = TP::to_point(&range.end, &snapshot);
 4495                            let start_point = TP::to_point(&range.start, &snapshot);
 4496                            (start_point..end_point, text)
 4497                        })
 4498                        .sorted_by_key(|(range, _)| range.start);
 4499                    buffer.edit(edits, None, cx);
 4500                })
 4501            }
 4502            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4503            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4504            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4505            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4506                new_anchor_selections,
 4507                &map,
 4508            )
 4509            .zip(new_selection_deltas)
 4510            .map(|(selection, delta)| Selection {
 4511                id: selection.id,
 4512                start: selection.start + delta,
 4513                end: selection.end + delta,
 4514                reversed: selection.reversed,
 4515                goal: SelectionGoal::None,
 4516            })
 4517            .collect::<Vec<_>>();
 4518
 4519            let mut i = 0;
 4520            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4521                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4522                let start = map.buffer_snapshot().anchor_before(position);
 4523                let end = map.buffer_snapshot().anchor_after(position);
 4524                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4525                    match existing_state
 4526                        .range
 4527                        .start
 4528                        .cmp(&start, map.buffer_snapshot())
 4529                    {
 4530                        Ordering::Less => i += 1,
 4531                        Ordering::Greater => break,
 4532                        Ordering::Equal => {
 4533                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4534                                Ordering::Less => i += 1,
 4535                                Ordering::Equal => break,
 4536                                Ordering::Greater => break,
 4537                            }
 4538                        }
 4539                    }
 4540                }
 4541                this.autoclose_regions.insert(
 4542                    i,
 4543                    AutocloseRegion {
 4544                        selection_id,
 4545                        range: start..end,
 4546                        pair,
 4547                    },
 4548                );
 4549            }
 4550
 4551            let had_active_edit_prediction = this.has_active_edit_prediction();
 4552            this.change_selections(
 4553                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4554                window,
 4555                cx,
 4556                |s| s.select(new_selections),
 4557            );
 4558
 4559            if !bracket_inserted
 4560                && let Some(on_type_format_task) =
 4561                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4562            {
 4563                on_type_format_task.detach_and_log_err(cx);
 4564            }
 4565
 4566            let editor_settings = EditorSettings::get_global(cx);
 4567            if bracket_inserted
 4568                && (editor_settings.auto_signature_help
 4569                    || editor_settings.show_signature_help_after_edits)
 4570            {
 4571                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4572            }
 4573
 4574            let trigger_in_words =
 4575                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4576            if this.hard_wrap.is_some() {
 4577                let latest: Range<Point> = this.selections.newest(&map).range();
 4578                if latest.is_empty()
 4579                    && this
 4580                        .buffer()
 4581                        .read(cx)
 4582                        .snapshot(cx)
 4583                        .line_len(MultiBufferRow(latest.start.row))
 4584                        == latest.start.column
 4585                {
 4586                    this.rewrap_impl(
 4587                        RewrapOptions {
 4588                            override_language_settings: true,
 4589                            preserve_existing_whitespace: true,
 4590                        },
 4591                        cx,
 4592                    )
 4593                }
 4594            }
 4595            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4596            refresh_linked_ranges(this, window, cx);
 4597            this.refresh_edit_prediction(true, false, window, cx);
 4598            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4599        });
 4600    }
 4601
 4602    fn find_possible_emoji_shortcode_at_position(
 4603        snapshot: &MultiBufferSnapshot,
 4604        position: Point,
 4605    ) -> Option<String> {
 4606        let mut chars = Vec::new();
 4607        let mut found_colon = false;
 4608        for char in snapshot.reversed_chars_at(position).take(100) {
 4609            // Found a possible emoji shortcode in the middle of the buffer
 4610            if found_colon {
 4611                if char.is_whitespace() {
 4612                    chars.reverse();
 4613                    return Some(chars.iter().collect());
 4614                }
 4615                // If the previous character is not a whitespace, we are in the middle of a word
 4616                // and we only want to complete the shortcode if the word is made up of other emojis
 4617                let mut containing_word = String::new();
 4618                for ch in snapshot
 4619                    .reversed_chars_at(position)
 4620                    .skip(chars.len() + 1)
 4621                    .take(100)
 4622                {
 4623                    if ch.is_whitespace() {
 4624                        break;
 4625                    }
 4626                    containing_word.push(ch);
 4627                }
 4628                let containing_word = containing_word.chars().rev().collect::<String>();
 4629                if util::word_consists_of_emojis(containing_word.as_str()) {
 4630                    chars.reverse();
 4631                    return Some(chars.iter().collect());
 4632                }
 4633            }
 4634
 4635            if char.is_whitespace() || !char.is_ascii() {
 4636                return None;
 4637            }
 4638            if char == ':' {
 4639                found_colon = true;
 4640            } else {
 4641                chars.push(char);
 4642            }
 4643        }
 4644        // Found a possible emoji shortcode at the beginning of the buffer
 4645        chars.reverse();
 4646        Some(chars.iter().collect())
 4647    }
 4648
 4649    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4650        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4651        self.transact(window, cx, |this, window, cx| {
 4652            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4653                let selections = this
 4654                    .selections
 4655                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4656                let multi_buffer = this.buffer.read(cx);
 4657                let buffer = multi_buffer.snapshot(cx);
 4658                selections
 4659                    .iter()
 4660                    .map(|selection| {
 4661                        let start_point = selection.start.to_point(&buffer);
 4662                        let mut existing_indent =
 4663                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4664                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4665                        let start = selection.start;
 4666                        let end = selection.end;
 4667                        let selection_is_empty = start == end;
 4668                        let language_scope = buffer.language_scope_at(start);
 4669                        let (
 4670                            comment_delimiter,
 4671                            doc_delimiter,
 4672                            insert_extra_newline,
 4673                            indent_on_newline,
 4674                            indent_on_extra_newline,
 4675                        ) = if let Some(language) = &language_scope {
 4676                            let mut insert_extra_newline =
 4677                                insert_extra_newline_brackets(&buffer, start..end, language)
 4678                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4679
 4680                            // Comment extension on newline is allowed only for cursor selections
 4681                            let comment_delimiter = maybe!({
 4682                                if !selection_is_empty {
 4683                                    return None;
 4684                                }
 4685
 4686                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4687                                    return None;
 4688                                }
 4689
 4690                                let delimiters = language.line_comment_prefixes();
 4691                                let max_len_of_delimiter =
 4692                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4693                                let (snapshot, range) =
 4694                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4695
 4696                                let num_of_whitespaces = snapshot
 4697                                    .chars_for_range(range.clone())
 4698                                    .take_while(|c| c.is_whitespace())
 4699                                    .count();
 4700                                let comment_candidate = snapshot
 4701                                    .chars_for_range(range.clone())
 4702                                    .skip(num_of_whitespaces)
 4703                                    .take(max_len_of_delimiter)
 4704                                    .collect::<String>();
 4705                                let (delimiter, trimmed_len) = delimiters
 4706                                    .iter()
 4707                                    .filter_map(|delimiter| {
 4708                                        let prefix = delimiter.trim_end();
 4709                                        if comment_candidate.starts_with(prefix) {
 4710                                            Some((delimiter, prefix.len()))
 4711                                        } else {
 4712                                            None
 4713                                        }
 4714                                    })
 4715                                    .max_by_key(|(_, len)| *len)?;
 4716
 4717                                if let Some(BlockCommentConfig {
 4718                                    start: block_start, ..
 4719                                }) = language.block_comment()
 4720                                {
 4721                                    let block_start_trimmed = block_start.trim_end();
 4722                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4723                                        let line_content = snapshot
 4724                                            .chars_for_range(range)
 4725                                            .skip(num_of_whitespaces)
 4726                                            .take(block_start_trimmed.len())
 4727                                            .collect::<String>();
 4728
 4729                                        if line_content.starts_with(block_start_trimmed) {
 4730                                            return None;
 4731                                        }
 4732                                    }
 4733                                }
 4734
 4735                                let cursor_is_placed_after_comment_marker =
 4736                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4737                                if cursor_is_placed_after_comment_marker {
 4738                                    Some(delimiter.clone())
 4739                                } else {
 4740                                    None
 4741                                }
 4742                            });
 4743
 4744                            let mut indent_on_newline = IndentSize::spaces(0);
 4745                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4746
 4747                            let doc_delimiter = maybe!({
 4748                                if !selection_is_empty {
 4749                                    return None;
 4750                                }
 4751
 4752                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4753                                    return None;
 4754                                }
 4755
 4756                                let BlockCommentConfig {
 4757                                    start: start_tag,
 4758                                    end: end_tag,
 4759                                    prefix: delimiter,
 4760                                    tab_size: len,
 4761                                } = language.documentation_comment()?;
 4762                                let is_within_block_comment = buffer
 4763                                    .language_scope_at(start_point)
 4764                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4765                                if !is_within_block_comment {
 4766                                    return None;
 4767                                }
 4768
 4769                                let (snapshot, range) =
 4770                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4771
 4772                                let num_of_whitespaces = snapshot
 4773                                    .chars_for_range(range.clone())
 4774                                    .take_while(|c| c.is_whitespace())
 4775                                    .count();
 4776
 4777                                // 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.
 4778                                let column = start_point.column;
 4779                                let cursor_is_after_start_tag = {
 4780                                    let start_tag_len = start_tag.len();
 4781                                    let start_tag_line = snapshot
 4782                                        .chars_for_range(range.clone())
 4783                                        .skip(num_of_whitespaces)
 4784                                        .take(start_tag_len)
 4785                                        .collect::<String>();
 4786                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4787                                        num_of_whitespaces + start_tag_len <= column as usize
 4788                                    } else {
 4789                                        false
 4790                                    }
 4791                                };
 4792
 4793                                let cursor_is_after_delimiter = {
 4794                                    let delimiter_trim = delimiter.trim_end();
 4795                                    let delimiter_line = snapshot
 4796                                        .chars_for_range(range.clone())
 4797                                        .skip(num_of_whitespaces)
 4798                                        .take(delimiter_trim.len())
 4799                                        .collect::<String>();
 4800                                    if delimiter_line.starts_with(delimiter_trim) {
 4801                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4802                                    } else {
 4803                                        false
 4804                                    }
 4805                                };
 4806
 4807                                let cursor_is_before_end_tag_if_exists = {
 4808                                    let mut char_position = 0u32;
 4809                                    let mut end_tag_offset = None;
 4810
 4811                                    'outer: for chunk in snapshot.text_for_range(range) {
 4812                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4813                                            let chars_before_match =
 4814                                                chunk[..byte_pos].chars().count() as u32;
 4815                                            end_tag_offset =
 4816                                                Some(char_position + chars_before_match);
 4817                                            break 'outer;
 4818                                        }
 4819                                        char_position += chunk.chars().count() as u32;
 4820                                    }
 4821
 4822                                    if let Some(end_tag_offset) = end_tag_offset {
 4823                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4824                                        if cursor_is_after_start_tag {
 4825                                            if cursor_is_before_end_tag {
 4826                                                insert_extra_newline = true;
 4827                                            }
 4828                                            let cursor_is_at_start_of_end_tag =
 4829                                                column == end_tag_offset;
 4830                                            if cursor_is_at_start_of_end_tag {
 4831                                                indent_on_extra_newline.len = *len;
 4832                                            }
 4833                                        }
 4834                                        cursor_is_before_end_tag
 4835                                    } else {
 4836                                        true
 4837                                    }
 4838                                };
 4839
 4840                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4841                                    && cursor_is_before_end_tag_if_exists
 4842                                {
 4843                                    if cursor_is_after_start_tag {
 4844                                        indent_on_newline.len = *len;
 4845                                    }
 4846                                    Some(delimiter.clone())
 4847                                } else {
 4848                                    None
 4849                                }
 4850                            });
 4851
 4852                            (
 4853                                comment_delimiter,
 4854                                doc_delimiter,
 4855                                insert_extra_newline,
 4856                                indent_on_newline,
 4857                                indent_on_extra_newline,
 4858                            )
 4859                        } else {
 4860                            (
 4861                                None,
 4862                                None,
 4863                                false,
 4864                                IndentSize::default(),
 4865                                IndentSize::default(),
 4866                            )
 4867                        };
 4868
 4869                        let prevent_auto_indent = doc_delimiter.is_some();
 4870                        let delimiter = comment_delimiter.or(doc_delimiter);
 4871
 4872                        let capacity_for_delimiter =
 4873                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4874                        let mut new_text = String::with_capacity(
 4875                            1 + capacity_for_delimiter
 4876                                + existing_indent.len as usize
 4877                                + indent_on_newline.len as usize
 4878                                + indent_on_extra_newline.len as usize,
 4879                        );
 4880                        new_text.push('\n');
 4881                        new_text.extend(existing_indent.chars());
 4882                        new_text.extend(indent_on_newline.chars());
 4883
 4884                        if let Some(delimiter) = &delimiter {
 4885                            new_text.push_str(delimiter);
 4886                        }
 4887
 4888                        if insert_extra_newline {
 4889                            new_text.push('\n');
 4890                            new_text.extend(existing_indent.chars());
 4891                            new_text.extend(indent_on_extra_newline.chars());
 4892                        }
 4893
 4894                        let anchor = buffer.anchor_after(end);
 4895                        let new_selection = selection.map(|_| anchor);
 4896                        (
 4897                            ((start..end, new_text), prevent_auto_indent),
 4898                            (insert_extra_newline, new_selection),
 4899                        )
 4900                    })
 4901                    .unzip()
 4902            };
 4903
 4904            let mut auto_indent_edits = Vec::new();
 4905            let mut edits = Vec::new();
 4906            for (edit, prevent_auto_indent) in edits_with_flags {
 4907                if prevent_auto_indent {
 4908                    edits.push(edit);
 4909                } else {
 4910                    auto_indent_edits.push(edit);
 4911                }
 4912            }
 4913            if !edits.is_empty() {
 4914                this.edit(edits, cx);
 4915            }
 4916            if !auto_indent_edits.is_empty() {
 4917                this.edit_with_autoindent(auto_indent_edits, cx);
 4918            }
 4919
 4920            let buffer = this.buffer.read(cx).snapshot(cx);
 4921            let new_selections = selection_info
 4922                .into_iter()
 4923                .map(|(extra_newline_inserted, new_selection)| {
 4924                    let mut cursor = new_selection.end.to_point(&buffer);
 4925                    if extra_newline_inserted {
 4926                        cursor.row -= 1;
 4927                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4928                    }
 4929                    new_selection.map(|_| cursor)
 4930                })
 4931                .collect();
 4932
 4933            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4934            this.refresh_edit_prediction(true, false, window, cx);
 4935        });
 4936    }
 4937
 4938    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4939        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4940
 4941        let buffer = self.buffer.read(cx);
 4942        let snapshot = buffer.snapshot(cx);
 4943
 4944        let mut edits = Vec::new();
 4945        let mut rows = Vec::new();
 4946
 4947        for (rows_inserted, selection) in self
 4948            .selections
 4949            .all_adjusted(&self.display_snapshot(cx))
 4950            .into_iter()
 4951            .enumerate()
 4952        {
 4953            let cursor = selection.head();
 4954            let row = cursor.row;
 4955
 4956            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4957
 4958            let newline = "\n".to_string();
 4959            edits.push((start_of_line..start_of_line, newline));
 4960
 4961            rows.push(row + rows_inserted as u32);
 4962        }
 4963
 4964        self.transact(window, cx, |editor, window, cx| {
 4965            editor.edit(edits, cx);
 4966
 4967            editor.change_selections(Default::default(), window, cx, |s| {
 4968                let mut index = 0;
 4969                s.move_cursors_with(|map, _, _| {
 4970                    let row = rows[index];
 4971                    index += 1;
 4972
 4973                    let point = Point::new(row, 0);
 4974                    let boundary = map.next_line_boundary(point).1;
 4975                    let clipped = map.clip_point(boundary, Bias::Left);
 4976
 4977                    (clipped, SelectionGoal::None)
 4978                });
 4979            });
 4980
 4981            let mut indent_edits = Vec::new();
 4982            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4983            for row in rows {
 4984                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4985                for (row, indent) in indents {
 4986                    if indent.len == 0 {
 4987                        continue;
 4988                    }
 4989
 4990                    let text = match indent.kind {
 4991                        IndentKind::Space => " ".repeat(indent.len as usize),
 4992                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4993                    };
 4994                    let point = Point::new(row.0, 0);
 4995                    indent_edits.push((point..point, text));
 4996                }
 4997            }
 4998            editor.edit(indent_edits, cx);
 4999        });
 5000    }
 5001
 5002    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5003        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5004
 5005        let buffer = self.buffer.read(cx);
 5006        let snapshot = buffer.snapshot(cx);
 5007
 5008        let mut edits = Vec::new();
 5009        let mut rows = Vec::new();
 5010        let mut rows_inserted = 0;
 5011
 5012        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5013            let cursor = selection.head();
 5014            let row = cursor.row;
 5015
 5016            let point = Point::new(row + 1, 0);
 5017            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5018
 5019            let newline = "\n".to_string();
 5020            edits.push((start_of_line..start_of_line, newline));
 5021
 5022            rows_inserted += 1;
 5023            rows.push(row + rows_inserted);
 5024        }
 5025
 5026        self.transact(window, cx, |editor, window, cx| {
 5027            editor.edit(edits, cx);
 5028
 5029            editor.change_selections(Default::default(), window, cx, |s| {
 5030                let mut index = 0;
 5031                s.move_cursors_with(|map, _, _| {
 5032                    let row = rows[index];
 5033                    index += 1;
 5034
 5035                    let point = Point::new(row, 0);
 5036                    let boundary = map.next_line_boundary(point).1;
 5037                    let clipped = map.clip_point(boundary, Bias::Left);
 5038
 5039                    (clipped, SelectionGoal::None)
 5040                });
 5041            });
 5042
 5043            let mut indent_edits = Vec::new();
 5044            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5045            for row in rows {
 5046                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5047                for (row, indent) in indents {
 5048                    if indent.len == 0 {
 5049                        continue;
 5050                    }
 5051
 5052                    let text = match indent.kind {
 5053                        IndentKind::Space => " ".repeat(indent.len as usize),
 5054                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5055                    };
 5056                    let point = Point::new(row.0, 0);
 5057                    indent_edits.push((point..point, text));
 5058                }
 5059            }
 5060            editor.edit(indent_edits, cx);
 5061        });
 5062    }
 5063
 5064    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5065        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5066            original_indent_columns: Vec::new(),
 5067        });
 5068        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5069    }
 5070
 5071    fn insert_with_autoindent_mode(
 5072        &mut self,
 5073        text: &str,
 5074        autoindent_mode: Option<AutoindentMode>,
 5075        window: &mut Window,
 5076        cx: &mut Context<Self>,
 5077    ) {
 5078        if self.read_only(cx) {
 5079            return;
 5080        }
 5081
 5082        let text: Arc<str> = text.into();
 5083        self.transact(window, cx, |this, window, cx| {
 5084            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5085            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5086                let anchors = {
 5087                    let snapshot = buffer.read(cx);
 5088                    old_selections
 5089                        .iter()
 5090                        .map(|s| {
 5091                            let anchor = snapshot.anchor_after(s.head());
 5092                            s.map(|_| anchor)
 5093                        })
 5094                        .collect::<Vec<_>>()
 5095                };
 5096                buffer.edit(
 5097                    old_selections
 5098                        .iter()
 5099                        .map(|s| (s.start..s.end, text.clone())),
 5100                    autoindent_mode,
 5101                    cx,
 5102                );
 5103                anchors
 5104            });
 5105
 5106            this.change_selections(Default::default(), window, cx, |s| {
 5107                s.select_anchors(selection_anchors);
 5108            });
 5109
 5110            cx.notify();
 5111        });
 5112    }
 5113
 5114    fn trigger_completion_on_input(
 5115        &mut self,
 5116        text: &str,
 5117        trigger_in_words: bool,
 5118        window: &mut Window,
 5119        cx: &mut Context<Self>,
 5120    ) {
 5121        let completions_source = self
 5122            .context_menu
 5123            .borrow()
 5124            .as_ref()
 5125            .and_then(|menu| match menu {
 5126                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5127                CodeContextMenu::CodeActions(_) => None,
 5128            });
 5129
 5130        match completions_source {
 5131            Some(CompletionsMenuSource::Words { .. }) => {
 5132                self.open_or_update_completions_menu(
 5133                    Some(CompletionsMenuSource::Words {
 5134                        ignore_threshold: false,
 5135                    }),
 5136                    None,
 5137                    trigger_in_words,
 5138                    window,
 5139                    cx,
 5140                );
 5141            }
 5142            _ => self.open_or_update_completions_menu(
 5143                None,
 5144                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5145                true,
 5146                window,
 5147                cx,
 5148            ),
 5149        }
 5150    }
 5151
 5152    /// If any empty selections is touching the start of its innermost containing autoclose
 5153    /// region, expand it to select the brackets.
 5154    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5155        let selections = self
 5156            .selections
 5157            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5158        let buffer = self.buffer.read(cx).read(cx);
 5159        let new_selections = self
 5160            .selections_with_autoclose_regions(selections, &buffer)
 5161            .map(|(mut selection, region)| {
 5162                if !selection.is_empty() {
 5163                    return selection;
 5164                }
 5165
 5166                if let Some(region) = region {
 5167                    let mut range = region.range.to_offset(&buffer);
 5168                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5169                        range.start -= region.pair.start.len();
 5170                        if buffer.contains_str_at(range.start, &region.pair.start)
 5171                            && buffer.contains_str_at(range.end, &region.pair.end)
 5172                        {
 5173                            range.end += region.pair.end.len();
 5174                            selection.start = range.start;
 5175                            selection.end = range.end;
 5176
 5177                            return selection;
 5178                        }
 5179                    }
 5180                }
 5181
 5182                let always_treat_brackets_as_autoclosed = buffer
 5183                    .language_settings_at(selection.start, cx)
 5184                    .always_treat_brackets_as_autoclosed;
 5185
 5186                if !always_treat_brackets_as_autoclosed {
 5187                    return selection;
 5188                }
 5189
 5190                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5191                    for (pair, enabled) in scope.brackets() {
 5192                        if !enabled || !pair.close {
 5193                            continue;
 5194                        }
 5195
 5196                        if buffer.contains_str_at(selection.start, &pair.end) {
 5197                            let pair_start_len = pair.start.len();
 5198                            if buffer.contains_str_at(
 5199                                selection.start.saturating_sub_usize(pair_start_len),
 5200                                &pair.start,
 5201                            ) {
 5202                                selection.start -= pair_start_len;
 5203                                selection.end += pair.end.len();
 5204
 5205                                return selection;
 5206                            }
 5207                        }
 5208                    }
 5209                }
 5210
 5211                selection
 5212            })
 5213            .collect();
 5214
 5215        drop(buffer);
 5216        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5217            selections.select(new_selections)
 5218        });
 5219    }
 5220
 5221    /// Iterate the given selections, and for each one, find the smallest surrounding
 5222    /// autoclose region. This uses the ordering of the selections and the autoclose
 5223    /// regions to avoid repeated comparisons.
 5224    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5225        &'a self,
 5226        selections: impl IntoIterator<Item = Selection<D>>,
 5227        buffer: &'a MultiBufferSnapshot,
 5228    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5229        let mut i = 0;
 5230        let mut regions = self.autoclose_regions.as_slice();
 5231        selections.into_iter().map(move |selection| {
 5232            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5233
 5234            let mut enclosing = None;
 5235            while let Some(pair_state) = regions.get(i) {
 5236                if pair_state.range.end.to_offset(buffer) < range.start {
 5237                    regions = &regions[i + 1..];
 5238                    i = 0;
 5239                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5240                    break;
 5241                } else {
 5242                    if pair_state.selection_id == selection.id {
 5243                        enclosing = Some(pair_state);
 5244                    }
 5245                    i += 1;
 5246                }
 5247            }
 5248
 5249            (selection, enclosing)
 5250        })
 5251    }
 5252
 5253    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5254    fn invalidate_autoclose_regions(
 5255        &mut self,
 5256        mut selections: &[Selection<Anchor>],
 5257        buffer: &MultiBufferSnapshot,
 5258    ) {
 5259        self.autoclose_regions.retain(|state| {
 5260            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5261                return false;
 5262            }
 5263
 5264            let mut i = 0;
 5265            while let Some(selection) = selections.get(i) {
 5266                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5267                    selections = &selections[1..];
 5268                    continue;
 5269                }
 5270                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5271                    break;
 5272                }
 5273                if selection.id == state.selection_id {
 5274                    return true;
 5275                } else {
 5276                    i += 1;
 5277                }
 5278            }
 5279            false
 5280        });
 5281    }
 5282
 5283    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5284        let offset = position.to_offset(buffer);
 5285        let (word_range, kind) =
 5286            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5287        if offset > word_range.start && kind == Some(CharKind::Word) {
 5288            Some(
 5289                buffer
 5290                    .text_for_range(word_range.start..offset)
 5291                    .collect::<String>(),
 5292            )
 5293        } else {
 5294            None
 5295        }
 5296    }
 5297
 5298    pub fn visible_excerpts(
 5299        &self,
 5300        cx: &mut Context<Editor>,
 5301    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5302        let Some(project) = self.project() else {
 5303            return HashMap::default();
 5304        };
 5305        let project = project.read(cx);
 5306        let multi_buffer = self.buffer().read(cx);
 5307        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5308        let multi_buffer_visible_start = self
 5309            .scroll_manager
 5310            .anchor()
 5311            .anchor
 5312            .to_point(&multi_buffer_snapshot);
 5313        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5314            multi_buffer_visible_start
 5315                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5316            Bias::Left,
 5317        );
 5318        multi_buffer_snapshot
 5319            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5320            .into_iter()
 5321            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5322            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5323                let buffer_file = project::File::from_dyn(buffer.file())?;
 5324                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5325                let worktree_entry = buffer_worktree
 5326                    .read(cx)
 5327                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5328                if worktree_entry.is_ignored {
 5329                    None
 5330                } else {
 5331                    Some((
 5332                        excerpt_id,
 5333                        (
 5334                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5335                            buffer.version().clone(),
 5336                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5337                        ),
 5338                    ))
 5339                }
 5340            })
 5341            .collect()
 5342    }
 5343
 5344    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5345        TextLayoutDetails {
 5346            text_system: window.text_system().clone(),
 5347            editor_style: self.style.clone().unwrap(),
 5348            rem_size: window.rem_size(),
 5349            scroll_anchor: self.scroll_manager.anchor(),
 5350            visible_rows: self.visible_line_count(),
 5351            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5352        }
 5353    }
 5354
 5355    fn trigger_on_type_formatting(
 5356        &self,
 5357        input: String,
 5358        window: &mut Window,
 5359        cx: &mut Context<Self>,
 5360    ) -> Option<Task<Result<()>>> {
 5361        if input.len() != 1 {
 5362            return None;
 5363        }
 5364
 5365        let project = self.project()?;
 5366        let position = self.selections.newest_anchor().head();
 5367        let (buffer, buffer_position) = self
 5368            .buffer
 5369            .read(cx)
 5370            .text_anchor_for_position(position, cx)?;
 5371
 5372        let settings = language_settings::language_settings(
 5373            buffer
 5374                .read(cx)
 5375                .language_at(buffer_position)
 5376                .map(|l| l.name()),
 5377            buffer.read(cx).file(),
 5378            cx,
 5379        );
 5380        if !settings.use_on_type_format {
 5381            return None;
 5382        }
 5383
 5384        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5385        // hence we do LSP request & edit on host side only — add formats to host's history.
 5386        let push_to_lsp_host_history = true;
 5387        // If this is not the host, append its history with new edits.
 5388        let push_to_client_history = project.read(cx).is_via_collab();
 5389
 5390        let on_type_formatting = project.update(cx, |project, cx| {
 5391            project.on_type_format(
 5392                buffer.clone(),
 5393                buffer_position,
 5394                input,
 5395                push_to_lsp_host_history,
 5396                cx,
 5397            )
 5398        });
 5399        Some(cx.spawn_in(window, async move |editor, cx| {
 5400            if let Some(transaction) = on_type_formatting.await? {
 5401                if push_to_client_history {
 5402                    buffer
 5403                        .update(cx, |buffer, _| {
 5404                            buffer.push_transaction(transaction, Instant::now());
 5405                            buffer.finalize_last_transaction();
 5406                        })
 5407                        .ok();
 5408                }
 5409                editor.update(cx, |editor, cx| {
 5410                    editor.refresh_document_highlights(cx);
 5411                })?;
 5412            }
 5413            Ok(())
 5414        }))
 5415    }
 5416
 5417    pub fn show_word_completions(
 5418        &mut self,
 5419        _: &ShowWordCompletions,
 5420        window: &mut Window,
 5421        cx: &mut Context<Self>,
 5422    ) {
 5423        self.open_or_update_completions_menu(
 5424            Some(CompletionsMenuSource::Words {
 5425                ignore_threshold: true,
 5426            }),
 5427            None,
 5428            false,
 5429            window,
 5430            cx,
 5431        );
 5432    }
 5433
 5434    pub fn show_completions(
 5435        &mut self,
 5436        _: &ShowCompletions,
 5437        window: &mut Window,
 5438        cx: &mut Context<Self>,
 5439    ) {
 5440        self.open_or_update_completions_menu(None, None, false, window, cx);
 5441    }
 5442
 5443    fn open_or_update_completions_menu(
 5444        &mut self,
 5445        requested_source: Option<CompletionsMenuSource>,
 5446        trigger: Option<String>,
 5447        trigger_in_words: bool,
 5448        window: &mut Window,
 5449        cx: &mut Context<Self>,
 5450    ) {
 5451        if self.pending_rename.is_some() {
 5452            return;
 5453        }
 5454
 5455        let completions_source = self
 5456            .context_menu
 5457            .borrow()
 5458            .as_ref()
 5459            .and_then(|menu| match menu {
 5460                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5461                CodeContextMenu::CodeActions(_) => None,
 5462            });
 5463
 5464        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5465
 5466        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5467        // inserted and selected. To handle that case, the start of the selection is used so that
 5468        // the menu starts with all choices.
 5469        let position = self
 5470            .selections
 5471            .newest_anchor()
 5472            .start
 5473            .bias_right(&multibuffer_snapshot);
 5474        if position.diff_base_anchor.is_some() {
 5475            return;
 5476        }
 5477        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5478        let Some(buffer) = buffer_position
 5479            .buffer_id
 5480            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5481        else {
 5482            return;
 5483        };
 5484        let buffer_snapshot = buffer.read(cx).snapshot();
 5485
 5486        let query: Option<Arc<String>> =
 5487            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5488                .map(|query| query.into());
 5489
 5490        drop(multibuffer_snapshot);
 5491
 5492        // Hide the current completions menu when query is empty. Without this, cached
 5493        // completions from before the trigger char may be reused (#32774).
 5494        if query.is_none() {
 5495            let menu_is_open = matches!(
 5496                self.context_menu.borrow().as_ref(),
 5497                Some(CodeContextMenu::Completions(_))
 5498            );
 5499            if menu_is_open {
 5500                self.hide_context_menu(window, cx);
 5501            }
 5502        }
 5503
 5504        let mut ignore_word_threshold = false;
 5505        let provider = match requested_source {
 5506            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5507            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5508                ignore_word_threshold = ignore_threshold;
 5509                None
 5510            }
 5511            Some(CompletionsMenuSource::SnippetChoices)
 5512            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5513                log::error!("bug: SnippetChoices requested_source is not handled");
 5514                None
 5515            }
 5516        };
 5517
 5518        let sort_completions = provider
 5519            .as_ref()
 5520            .is_some_and(|provider| provider.sort_completions());
 5521
 5522        let filter_completions = provider
 5523            .as_ref()
 5524            .is_none_or(|provider| provider.filter_completions());
 5525
 5526        let was_snippets_only = matches!(
 5527            completions_source,
 5528            Some(CompletionsMenuSource::SnippetsOnly)
 5529        );
 5530
 5531        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5532            if filter_completions {
 5533                menu.filter(
 5534                    query.clone().unwrap_or_default(),
 5535                    buffer_position.text_anchor,
 5536                    &buffer,
 5537                    provider.clone(),
 5538                    window,
 5539                    cx,
 5540                );
 5541            }
 5542            // When `is_incomplete` is false, no need to re-query completions when the current query
 5543            // is a suffix of the initial query.
 5544            let was_complete = !menu.is_incomplete;
 5545            if was_complete && !was_snippets_only {
 5546                // If the new query is a suffix of the old query (typing more characters) and
 5547                // the previous result was complete, the existing completions can be filtered.
 5548                //
 5549                // Note that snippet completions are always complete.
 5550                let query_matches = match (&menu.initial_query, &query) {
 5551                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5552                    (None, _) => true,
 5553                    _ => false,
 5554                };
 5555                if query_matches {
 5556                    let position_matches = if menu.initial_position == position {
 5557                        true
 5558                    } else {
 5559                        let snapshot = self.buffer.read(cx).read(cx);
 5560                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5561                    };
 5562                    if position_matches {
 5563                        return;
 5564                    }
 5565                }
 5566            }
 5567        };
 5568
 5569        let Anchor {
 5570            excerpt_id: buffer_excerpt_id,
 5571            text_anchor: buffer_position,
 5572            ..
 5573        } = buffer_position;
 5574
 5575        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5576            buffer_snapshot.surrounding_word(buffer_position, None)
 5577        {
 5578            let word_to_exclude = buffer_snapshot
 5579                .text_for_range(word_range.clone())
 5580                .collect::<String>();
 5581            (
 5582                buffer_snapshot.anchor_before(word_range.start)
 5583                    ..buffer_snapshot.anchor_after(buffer_position),
 5584                Some(word_to_exclude),
 5585            )
 5586        } else {
 5587            (buffer_position..buffer_position, None)
 5588        };
 5589
 5590        let language = buffer_snapshot
 5591            .language_at(buffer_position)
 5592            .map(|language| language.name());
 5593
 5594        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5595            .completions
 5596            .clone();
 5597
 5598        let show_completion_documentation = buffer_snapshot
 5599            .settings_at(buffer_position, cx)
 5600            .show_completion_documentation;
 5601
 5602        // The document can be large, so stay in reasonable bounds when searching for words,
 5603        // otherwise completion pop-up might be slow to appear.
 5604        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5605        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5606        let min_word_search = buffer_snapshot.clip_point(
 5607            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5608            Bias::Left,
 5609        );
 5610        let max_word_search = buffer_snapshot.clip_point(
 5611            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5612            Bias::Right,
 5613        );
 5614        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5615            ..buffer_snapshot.point_to_offset(max_word_search);
 5616
 5617        let skip_digits = query
 5618            .as_ref()
 5619            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5620
 5621        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5622            trigger.as_ref().is_none_or(|trigger| {
 5623                provider.is_completion_trigger(
 5624                    &buffer,
 5625                    position.text_anchor,
 5626                    trigger,
 5627                    trigger_in_words,
 5628                    completions_source.is_some(),
 5629                    cx,
 5630                )
 5631            })
 5632        });
 5633
 5634        let provider_responses = if let Some(provider) = &provider
 5635            && load_provider_completions
 5636        {
 5637            let trigger_character =
 5638                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5639            let completion_context = CompletionContext {
 5640                trigger_kind: match &trigger_character {
 5641                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5642                    None => CompletionTriggerKind::INVOKED,
 5643                },
 5644                trigger_character,
 5645            };
 5646
 5647            provider.completions(
 5648                buffer_excerpt_id,
 5649                &buffer,
 5650                buffer_position,
 5651                completion_context,
 5652                window,
 5653                cx,
 5654            )
 5655        } else {
 5656            Task::ready(Ok(Vec::new()))
 5657        };
 5658
 5659        let load_word_completions = if !self.word_completions_enabled {
 5660            false
 5661        } else if requested_source
 5662            == Some(CompletionsMenuSource::Words {
 5663                ignore_threshold: true,
 5664            })
 5665        {
 5666            true
 5667        } else {
 5668            load_provider_completions
 5669                && completion_settings.words != WordsCompletionMode::Disabled
 5670                && (ignore_word_threshold || {
 5671                    let words_min_length = completion_settings.words_min_length;
 5672                    // check whether word has at least `words_min_length` characters
 5673                    let query_chars = query.iter().flat_map(|q| q.chars());
 5674                    query_chars.take(words_min_length).count() == words_min_length
 5675                })
 5676        };
 5677
 5678        let mut words = if load_word_completions {
 5679            cx.background_spawn({
 5680                let buffer_snapshot = buffer_snapshot.clone();
 5681                async move {
 5682                    buffer_snapshot.words_in_range(WordsQuery {
 5683                        fuzzy_contents: None,
 5684                        range: word_search_range,
 5685                        skip_digits,
 5686                    })
 5687                }
 5688            })
 5689        } else {
 5690            Task::ready(BTreeMap::default())
 5691        };
 5692
 5693        let snippets = if let Some(provider) = &provider
 5694            && provider.show_snippets()
 5695            && let Some(project) = self.project()
 5696        {
 5697            let char_classifier = buffer_snapshot
 5698                .char_classifier_at(buffer_position)
 5699                .scope_context(Some(CharScopeContext::Completion));
 5700            project.update(cx, |project, cx| {
 5701                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5702            })
 5703        } else {
 5704            Task::ready(Ok(CompletionResponse {
 5705                completions: Vec::new(),
 5706                display_options: Default::default(),
 5707                is_incomplete: false,
 5708            }))
 5709        };
 5710
 5711        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5712
 5713        let id = post_inc(&mut self.next_completion_id);
 5714        let task = cx.spawn_in(window, async move |editor, cx| {
 5715            let Ok(()) = editor.update(cx, |this, _| {
 5716                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5717            }) else {
 5718                return;
 5719            };
 5720
 5721            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5722            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5723            let mut completions = Vec::new();
 5724            let mut is_incomplete = false;
 5725            let mut display_options: Option<CompletionDisplayOptions> = None;
 5726            if let Some(provider_responses) = provider_responses.await.log_err()
 5727                && !provider_responses.is_empty()
 5728            {
 5729                for response in provider_responses {
 5730                    completions.extend(response.completions);
 5731                    is_incomplete = is_incomplete || response.is_incomplete;
 5732                    match display_options.as_mut() {
 5733                        None => {
 5734                            display_options = Some(response.display_options);
 5735                        }
 5736                        Some(options) => options.merge(&response.display_options),
 5737                    }
 5738                }
 5739                if completion_settings.words == WordsCompletionMode::Fallback {
 5740                    words = Task::ready(BTreeMap::default());
 5741                }
 5742            }
 5743            let display_options = display_options.unwrap_or_default();
 5744
 5745            let mut words = words.await;
 5746            if let Some(word_to_exclude) = &word_to_exclude {
 5747                words.remove(word_to_exclude);
 5748            }
 5749            for lsp_completion in &completions {
 5750                words.remove(&lsp_completion.new_text);
 5751            }
 5752            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5753                replace_range: word_replace_range.clone(),
 5754                new_text: word.clone(),
 5755                label: CodeLabel::plain(word, None),
 5756                match_start: None,
 5757                snippet_deduplication_key: None,
 5758                icon_path: None,
 5759                documentation: None,
 5760                source: CompletionSource::BufferWord {
 5761                    word_range,
 5762                    resolved: false,
 5763                },
 5764                insert_text_mode: Some(InsertTextMode::AS_IS),
 5765                confirm: None,
 5766            }));
 5767
 5768            completions.extend(
 5769                snippets
 5770                    .await
 5771                    .into_iter()
 5772                    .flat_map(|response| response.completions),
 5773            );
 5774
 5775            let menu = if completions.is_empty() {
 5776                None
 5777            } else {
 5778                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5779                    let languages = editor
 5780                        .workspace
 5781                        .as_ref()
 5782                        .and_then(|(workspace, _)| workspace.upgrade())
 5783                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5784                    let menu = CompletionsMenu::new(
 5785                        id,
 5786                        requested_source.unwrap_or(if load_provider_completions {
 5787                            CompletionsMenuSource::Normal
 5788                        } else {
 5789                            CompletionsMenuSource::SnippetsOnly
 5790                        }),
 5791                        sort_completions,
 5792                        show_completion_documentation,
 5793                        position,
 5794                        query.clone(),
 5795                        is_incomplete,
 5796                        buffer.clone(),
 5797                        completions.into(),
 5798                        display_options,
 5799                        snippet_sort_order,
 5800                        languages,
 5801                        language,
 5802                        cx,
 5803                    );
 5804
 5805                    let query = if filter_completions { query } else { None };
 5806                    let matches_task = menu.do_async_filtering(
 5807                        query.unwrap_or_default(),
 5808                        buffer_position,
 5809                        &buffer,
 5810                        cx,
 5811                    );
 5812                    (menu, matches_task)
 5813                }) else {
 5814                    return;
 5815                };
 5816
 5817                let matches = matches_task.await;
 5818
 5819                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5820                    // Newer menu already set, so exit.
 5821                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5822                        editor.context_menu.borrow().as_ref()
 5823                        && prev_menu.id > id
 5824                    {
 5825                        return;
 5826                    };
 5827
 5828                    // Only valid to take prev_menu because either the new menu is immediately set
 5829                    // below, or the menu is hidden.
 5830                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5831                        editor.context_menu.borrow_mut().take()
 5832                    {
 5833                        let position_matches =
 5834                            if prev_menu.initial_position == menu.initial_position {
 5835                                true
 5836                            } else {
 5837                                let snapshot = editor.buffer.read(cx).read(cx);
 5838                                prev_menu.initial_position.to_offset(&snapshot)
 5839                                    == menu.initial_position.to_offset(&snapshot)
 5840                            };
 5841                        if position_matches {
 5842                            // Preserve markdown cache before `set_filter_results` because it will
 5843                            // try to populate the documentation cache.
 5844                            menu.preserve_markdown_cache(prev_menu);
 5845                        }
 5846                    };
 5847
 5848                    menu.set_filter_results(matches, provider, window, cx);
 5849                }) else {
 5850                    return;
 5851                };
 5852
 5853                menu.visible().then_some(menu)
 5854            };
 5855
 5856            editor
 5857                .update_in(cx, |editor, window, cx| {
 5858                    if editor.focus_handle.is_focused(window)
 5859                        && let Some(menu) = menu
 5860                    {
 5861                        *editor.context_menu.borrow_mut() =
 5862                            Some(CodeContextMenu::Completions(menu));
 5863
 5864                        crate::hover_popover::hide_hover(editor, cx);
 5865                        if editor.show_edit_predictions_in_menu() {
 5866                            editor.update_visible_edit_prediction(window, cx);
 5867                        } else {
 5868                            editor.discard_edit_prediction(false, cx);
 5869                        }
 5870
 5871                        cx.notify();
 5872                        return;
 5873                    }
 5874
 5875                    if editor.completion_tasks.len() <= 1 {
 5876                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5877                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5878                        // If it was already hidden and we don't show edit predictions in the menu,
 5879                        // we should also show the edit prediction when available.
 5880                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5881                            editor.update_visible_edit_prediction(window, cx);
 5882                        }
 5883                    }
 5884                })
 5885                .ok();
 5886        });
 5887
 5888        self.completion_tasks.push((id, task));
 5889    }
 5890
 5891    #[cfg(feature = "test-support")]
 5892    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5893        let menu = self.context_menu.borrow();
 5894        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5895            let completions = menu.completions.borrow();
 5896            Some(completions.to_vec())
 5897        } else {
 5898            None
 5899        }
 5900    }
 5901
 5902    pub fn with_completions_menu_matching_id<R>(
 5903        &self,
 5904        id: CompletionId,
 5905        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5906    ) -> R {
 5907        let mut context_menu = self.context_menu.borrow_mut();
 5908        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5909            return f(None);
 5910        };
 5911        if completions_menu.id != id {
 5912            return f(None);
 5913        }
 5914        f(Some(completions_menu))
 5915    }
 5916
 5917    pub fn confirm_completion(
 5918        &mut self,
 5919        action: &ConfirmCompletion,
 5920        window: &mut Window,
 5921        cx: &mut Context<Self>,
 5922    ) -> Option<Task<Result<()>>> {
 5923        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5924        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5925    }
 5926
 5927    pub fn confirm_completion_insert(
 5928        &mut self,
 5929        _: &ConfirmCompletionInsert,
 5930        window: &mut Window,
 5931        cx: &mut Context<Self>,
 5932    ) -> Option<Task<Result<()>>> {
 5933        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5934        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5935    }
 5936
 5937    pub fn confirm_completion_replace(
 5938        &mut self,
 5939        _: &ConfirmCompletionReplace,
 5940        window: &mut Window,
 5941        cx: &mut Context<Self>,
 5942    ) -> Option<Task<Result<()>>> {
 5943        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5944        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5945    }
 5946
 5947    pub fn compose_completion(
 5948        &mut self,
 5949        action: &ComposeCompletion,
 5950        window: &mut Window,
 5951        cx: &mut Context<Self>,
 5952    ) -> Option<Task<Result<()>>> {
 5953        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5954        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5955    }
 5956
 5957    fn do_completion(
 5958        &mut self,
 5959        item_ix: Option<usize>,
 5960        intent: CompletionIntent,
 5961        window: &mut Window,
 5962        cx: &mut Context<Editor>,
 5963    ) -> Option<Task<Result<()>>> {
 5964        use language::ToOffset as _;
 5965
 5966        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5967        else {
 5968            return None;
 5969        };
 5970
 5971        let candidate_id = {
 5972            let entries = completions_menu.entries.borrow();
 5973            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5974            if self.show_edit_predictions_in_menu() {
 5975                self.discard_edit_prediction(true, cx);
 5976            }
 5977            mat.candidate_id
 5978        };
 5979
 5980        let completion = completions_menu
 5981            .completions
 5982            .borrow()
 5983            .get(candidate_id)?
 5984            .clone();
 5985        cx.stop_propagation();
 5986
 5987        let buffer_handle = completions_menu.buffer.clone();
 5988
 5989        let CompletionEdit {
 5990            new_text,
 5991            snippet,
 5992            replace_range,
 5993        } = process_completion_for_edit(
 5994            &completion,
 5995            intent,
 5996            &buffer_handle,
 5997            &completions_menu.initial_position.text_anchor,
 5998            cx,
 5999        );
 6000
 6001        let buffer = buffer_handle.read(cx);
 6002        let snapshot = self.buffer.read(cx).snapshot(cx);
 6003        let newest_anchor = self.selections.newest_anchor();
 6004        let replace_range_multibuffer = {
 6005            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6006            excerpt.map_range_from_buffer(replace_range.clone())
 6007        };
 6008        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6009            return None;
 6010        }
 6011
 6012        let old_text = buffer
 6013            .text_for_range(replace_range.clone())
 6014            .collect::<String>();
 6015        let lookbehind = newest_anchor
 6016            .start
 6017            .text_anchor
 6018            .to_offset(buffer)
 6019            .saturating_sub(replace_range.start.0);
 6020        let lookahead = replace_range
 6021            .end
 6022            .0
 6023            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6024        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6025        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6026
 6027        let selections = self
 6028            .selections
 6029            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6030        let mut ranges = Vec::new();
 6031        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6032
 6033        for selection in &selections {
 6034            let range = if selection.id == newest_anchor.id {
 6035                replace_range_multibuffer.clone()
 6036            } else {
 6037                let mut range = selection.range();
 6038
 6039                // if prefix is present, don't duplicate it
 6040                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6041                    range.start = range.start.saturating_sub_usize(lookbehind);
 6042
 6043                    // if suffix is also present, mimic the newest cursor and replace it
 6044                    if selection.id != newest_anchor.id
 6045                        && snapshot.contains_str_at(range.end, suffix)
 6046                    {
 6047                        range.end += lookahead;
 6048                    }
 6049                }
 6050                range
 6051            };
 6052
 6053            ranges.push(range.clone());
 6054
 6055            if !self.linked_edit_ranges.is_empty() {
 6056                let start_anchor = snapshot.anchor_before(range.start);
 6057                let end_anchor = snapshot.anchor_after(range.end);
 6058                if let Some(ranges) = self
 6059                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6060                {
 6061                    for (buffer, edits) in ranges {
 6062                        linked_edits
 6063                            .entry(buffer.clone())
 6064                            .or_default()
 6065                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6066                    }
 6067                }
 6068            }
 6069        }
 6070
 6071        let common_prefix_len = old_text
 6072            .chars()
 6073            .zip(new_text.chars())
 6074            .take_while(|(a, b)| a == b)
 6075            .map(|(a, _)| a.len_utf8())
 6076            .sum::<usize>();
 6077
 6078        cx.emit(EditorEvent::InputHandled {
 6079            utf16_range_to_replace: None,
 6080            text: new_text[common_prefix_len..].into(),
 6081        });
 6082
 6083        self.transact(window, cx, |editor, window, cx| {
 6084            if let Some(mut snippet) = snippet {
 6085                snippet.text = new_text.to_string();
 6086                editor
 6087                    .insert_snippet(&ranges, snippet, window, cx)
 6088                    .log_err();
 6089            } else {
 6090                editor.buffer.update(cx, |multi_buffer, cx| {
 6091                    let auto_indent = match completion.insert_text_mode {
 6092                        Some(InsertTextMode::AS_IS) => None,
 6093                        _ => editor.autoindent_mode.clone(),
 6094                    };
 6095                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6096                    multi_buffer.edit(edits, auto_indent, cx);
 6097                });
 6098            }
 6099            for (buffer, edits) in linked_edits {
 6100                buffer.update(cx, |buffer, cx| {
 6101                    let snapshot = buffer.snapshot();
 6102                    let edits = edits
 6103                        .into_iter()
 6104                        .map(|(range, text)| {
 6105                            use text::ToPoint as TP;
 6106                            let end_point = TP::to_point(&range.end, &snapshot);
 6107                            let start_point = TP::to_point(&range.start, &snapshot);
 6108                            (start_point..end_point, text)
 6109                        })
 6110                        .sorted_by_key(|(range, _)| range.start);
 6111                    buffer.edit(edits, None, cx);
 6112                })
 6113            }
 6114
 6115            editor.refresh_edit_prediction(true, false, window, cx);
 6116        });
 6117        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6118
 6119        let show_new_completions_on_confirm = completion
 6120            .confirm
 6121            .as_ref()
 6122            .is_some_and(|confirm| confirm(intent, window, cx));
 6123        if show_new_completions_on_confirm {
 6124            self.open_or_update_completions_menu(None, None, false, window, cx);
 6125        }
 6126
 6127        let provider = self.completion_provider.as_ref()?;
 6128        drop(completion);
 6129        let apply_edits = provider.apply_additional_edits_for_completion(
 6130            buffer_handle,
 6131            completions_menu.completions.clone(),
 6132            candidate_id,
 6133            true,
 6134            cx,
 6135        );
 6136
 6137        let editor_settings = EditorSettings::get_global(cx);
 6138        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6139            // After the code completion is finished, users often want to know what signatures are needed.
 6140            // so we should automatically call signature_help
 6141            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6142        }
 6143
 6144        Some(cx.foreground_executor().spawn(async move {
 6145            apply_edits.await?;
 6146            Ok(())
 6147        }))
 6148    }
 6149
 6150    pub fn toggle_code_actions(
 6151        &mut self,
 6152        action: &ToggleCodeActions,
 6153        window: &mut Window,
 6154        cx: &mut Context<Self>,
 6155    ) {
 6156        let quick_launch = action.quick_launch;
 6157        let mut context_menu = self.context_menu.borrow_mut();
 6158        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6159            if code_actions.deployed_from == action.deployed_from {
 6160                // Toggle if we're selecting the same one
 6161                *context_menu = None;
 6162                cx.notify();
 6163                return;
 6164            } else {
 6165                // Otherwise, clear it and start a new one
 6166                *context_menu = None;
 6167                cx.notify();
 6168            }
 6169        }
 6170        drop(context_menu);
 6171        let snapshot = self.snapshot(window, cx);
 6172        let deployed_from = action.deployed_from.clone();
 6173        let action = action.clone();
 6174        self.completion_tasks.clear();
 6175        self.discard_edit_prediction(false, cx);
 6176
 6177        let multibuffer_point = match &action.deployed_from {
 6178            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6179                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6180            }
 6181            _ => self
 6182                .selections
 6183                .newest::<Point>(&snapshot.display_snapshot)
 6184                .head(),
 6185        };
 6186        let Some((buffer, buffer_row)) = snapshot
 6187            .buffer_snapshot()
 6188            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6189            .and_then(|(buffer_snapshot, range)| {
 6190                self.buffer()
 6191                    .read(cx)
 6192                    .buffer(buffer_snapshot.remote_id())
 6193                    .map(|buffer| (buffer, range.start.row))
 6194            })
 6195        else {
 6196            return;
 6197        };
 6198        let buffer_id = buffer.read(cx).remote_id();
 6199        let tasks = self
 6200            .tasks
 6201            .get(&(buffer_id, buffer_row))
 6202            .map(|t| Arc::new(t.to_owned()));
 6203
 6204        if !self.focus_handle.is_focused(window) {
 6205            return;
 6206        }
 6207        let project = self.project.clone();
 6208
 6209        let code_actions_task = match deployed_from {
 6210            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6211            _ => self.code_actions(buffer_row, window, cx),
 6212        };
 6213
 6214        let runnable_task = match deployed_from {
 6215            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6216            _ => {
 6217                let mut task_context_task = Task::ready(None);
 6218                if let Some(tasks) = &tasks
 6219                    && let Some(project) = project
 6220                {
 6221                    task_context_task =
 6222                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6223                }
 6224
 6225                cx.spawn_in(window, {
 6226                    let buffer = buffer.clone();
 6227                    async move |editor, cx| {
 6228                        let task_context = task_context_task.await;
 6229
 6230                        let resolved_tasks =
 6231                            tasks
 6232                                .zip(task_context.clone())
 6233                                .map(|(tasks, task_context)| ResolvedTasks {
 6234                                    templates: tasks.resolve(&task_context).collect(),
 6235                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6236                                        multibuffer_point.row,
 6237                                        tasks.column,
 6238                                    )),
 6239                                });
 6240                        let debug_scenarios = editor
 6241                            .update(cx, |editor, cx| {
 6242                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6243                            })?
 6244                            .await;
 6245                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6246                    }
 6247                })
 6248            }
 6249        };
 6250
 6251        cx.spawn_in(window, async move |editor, cx| {
 6252            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6253            let code_actions = code_actions_task.await;
 6254            let spawn_straight_away = quick_launch
 6255                && resolved_tasks
 6256                    .as_ref()
 6257                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6258                && code_actions
 6259                    .as_ref()
 6260                    .is_none_or(|actions| actions.is_empty())
 6261                && debug_scenarios.is_empty();
 6262
 6263            editor.update_in(cx, |editor, window, cx| {
 6264                crate::hover_popover::hide_hover(editor, cx);
 6265                let actions = CodeActionContents::new(
 6266                    resolved_tasks,
 6267                    code_actions,
 6268                    debug_scenarios,
 6269                    task_context.unwrap_or_default(),
 6270                );
 6271
 6272                // Don't show the menu if there are no actions available
 6273                if actions.is_empty() {
 6274                    cx.notify();
 6275                    return Task::ready(Ok(()));
 6276                }
 6277
 6278                *editor.context_menu.borrow_mut() =
 6279                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6280                        buffer,
 6281                        actions,
 6282                        selected_item: Default::default(),
 6283                        scroll_handle: UniformListScrollHandle::default(),
 6284                        deployed_from,
 6285                    }));
 6286                cx.notify();
 6287                if spawn_straight_away
 6288                    && let Some(task) = editor.confirm_code_action(
 6289                        &ConfirmCodeAction { item_ix: Some(0) },
 6290                        window,
 6291                        cx,
 6292                    )
 6293                {
 6294                    return task;
 6295                }
 6296
 6297                Task::ready(Ok(()))
 6298            })
 6299        })
 6300        .detach_and_log_err(cx);
 6301    }
 6302
 6303    fn debug_scenarios(
 6304        &mut self,
 6305        resolved_tasks: &Option<ResolvedTasks>,
 6306        buffer: &Entity<Buffer>,
 6307        cx: &mut App,
 6308    ) -> Task<Vec<task::DebugScenario>> {
 6309        maybe!({
 6310            let project = self.project()?;
 6311            let dap_store = project.read(cx).dap_store();
 6312            let mut scenarios = vec![];
 6313            let resolved_tasks = resolved_tasks.as_ref()?;
 6314            let buffer = buffer.read(cx);
 6315            let language = buffer.language()?;
 6316            let file = buffer.file();
 6317            let debug_adapter = language_settings(language.name().into(), file, cx)
 6318                .debuggers
 6319                .first()
 6320                .map(SharedString::from)
 6321                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6322
 6323            dap_store.update(cx, |dap_store, cx| {
 6324                for (_, task) in &resolved_tasks.templates {
 6325                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6326                        task.original_task().clone(),
 6327                        debug_adapter.clone().into(),
 6328                        task.display_label().to_owned().into(),
 6329                        cx,
 6330                    );
 6331                    scenarios.push(maybe_scenario);
 6332                }
 6333            });
 6334            Some(cx.background_spawn(async move {
 6335                futures::future::join_all(scenarios)
 6336                    .await
 6337                    .into_iter()
 6338                    .flatten()
 6339                    .collect::<Vec<_>>()
 6340            }))
 6341        })
 6342        .unwrap_or_else(|| Task::ready(vec![]))
 6343    }
 6344
 6345    fn code_actions(
 6346        &mut self,
 6347        buffer_row: u32,
 6348        window: &mut Window,
 6349        cx: &mut Context<Self>,
 6350    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6351        let mut task = self.code_actions_task.take();
 6352        cx.spawn_in(window, async move |editor, cx| {
 6353            while let Some(prev_task) = task {
 6354                prev_task.await.log_err();
 6355                task = editor
 6356                    .update(cx, |this, _| this.code_actions_task.take())
 6357                    .ok()?;
 6358            }
 6359
 6360            editor
 6361                .update(cx, |editor, cx| {
 6362                    editor
 6363                        .available_code_actions
 6364                        .clone()
 6365                        .and_then(|(location, code_actions)| {
 6366                            let snapshot = location.buffer.read(cx).snapshot();
 6367                            let point_range = location.range.to_point(&snapshot);
 6368                            let point_range = point_range.start.row..=point_range.end.row;
 6369                            if point_range.contains(&buffer_row) {
 6370                                Some(code_actions)
 6371                            } else {
 6372                                None
 6373                            }
 6374                        })
 6375                })
 6376                .ok()
 6377                .flatten()
 6378        })
 6379    }
 6380
 6381    pub fn confirm_code_action(
 6382        &mut self,
 6383        action: &ConfirmCodeAction,
 6384        window: &mut Window,
 6385        cx: &mut Context<Self>,
 6386    ) -> Option<Task<Result<()>>> {
 6387        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6388
 6389        let actions_menu =
 6390            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6391                menu
 6392            } else {
 6393                return None;
 6394            };
 6395
 6396        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6397        let action = actions_menu.actions.get(action_ix)?;
 6398        let title = action.label();
 6399        let buffer = actions_menu.buffer;
 6400        let workspace = self.workspace()?;
 6401
 6402        match action {
 6403            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6404                workspace.update(cx, |workspace, cx| {
 6405                    workspace.schedule_resolved_task(
 6406                        task_source_kind,
 6407                        resolved_task,
 6408                        false,
 6409                        window,
 6410                        cx,
 6411                    );
 6412
 6413                    Some(Task::ready(Ok(())))
 6414                })
 6415            }
 6416            CodeActionsItem::CodeAction {
 6417                excerpt_id,
 6418                action,
 6419                provider,
 6420            } => {
 6421                let apply_code_action =
 6422                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6423                let workspace = workspace.downgrade();
 6424                Some(cx.spawn_in(window, async move |editor, cx| {
 6425                    let project_transaction = apply_code_action.await?;
 6426                    Self::open_project_transaction(
 6427                        &editor,
 6428                        workspace,
 6429                        project_transaction,
 6430                        title,
 6431                        cx,
 6432                    )
 6433                    .await
 6434                }))
 6435            }
 6436            CodeActionsItem::DebugScenario(scenario) => {
 6437                let context = actions_menu.actions.context;
 6438
 6439                workspace.update(cx, |workspace, cx| {
 6440                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6441                    workspace.start_debug_session(
 6442                        scenario,
 6443                        context,
 6444                        Some(buffer),
 6445                        None,
 6446                        window,
 6447                        cx,
 6448                    );
 6449                });
 6450                Some(Task::ready(Ok(())))
 6451            }
 6452        }
 6453    }
 6454
 6455    pub async fn open_project_transaction(
 6456        editor: &WeakEntity<Editor>,
 6457        workspace: WeakEntity<Workspace>,
 6458        transaction: ProjectTransaction,
 6459        title: String,
 6460        cx: &mut AsyncWindowContext,
 6461    ) -> Result<()> {
 6462        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6463        cx.update(|_, cx| {
 6464            entries.sort_unstable_by_key(|(buffer, _)| {
 6465                buffer.read(cx).file().map(|f| f.path().clone())
 6466            });
 6467        })?;
 6468        if entries.is_empty() {
 6469            return Ok(());
 6470        }
 6471
 6472        // If the project transaction's edits are all contained within this editor, then
 6473        // avoid opening a new editor to display them.
 6474
 6475        if let [(buffer, transaction)] = &*entries {
 6476            let excerpt = editor.update(cx, |editor, cx| {
 6477                editor
 6478                    .buffer()
 6479                    .read(cx)
 6480                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6481            })?;
 6482            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6483                && excerpted_buffer == *buffer
 6484            {
 6485                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6486                    let excerpt_range = excerpt_range.to_offset(buffer);
 6487                    buffer
 6488                        .edited_ranges_for_transaction::<usize>(transaction)
 6489                        .all(|range| {
 6490                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6491                        })
 6492                })?;
 6493
 6494                if all_edits_within_excerpt {
 6495                    return Ok(());
 6496                }
 6497            }
 6498        }
 6499
 6500        let mut ranges_to_highlight = Vec::new();
 6501        let excerpt_buffer = cx.new(|cx| {
 6502            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6503            for (buffer_handle, transaction) in &entries {
 6504                let edited_ranges = buffer_handle
 6505                    .read(cx)
 6506                    .edited_ranges_for_transaction::<Point>(transaction)
 6507                    .collect::<Vec<_>>();
 6508                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6509                    PathKey::for_buffer(buffer_handle, cx),
 6510                    buffer_handle.clone(),
 6511                    edited_ranges,
 6512                    multibuffer_context_lines(cx),
 6513                    cx,
 6514                );
 6515
 6516                ranges_to_highlight.extend(ranges);
 6517            }
 6518            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6519            multibuffer
 6520        })?;
 6521
 6522        workspace.update_in(cx, |workspace, window, cx| {
 6523            let project = workspace.project().clone();
 6524            let editor =
 6525                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6526            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6527            editor.update(cx, |editor, cx| {
 6528                editor.highlight_background::<Self>(
 6529                    &ranges_to_highlight,
 6530                    |theme| theme.colors().editor_highlighted_line_background,
 6531                    cx,
 6532                );
 6533            });
 6534        })?;
 6535
 6536        Ok(())
 6537    }
 6538
 6539    pub fn clear_code_action_providers(&mut self) {
 6540        self.code_action_providers.clear();
 6541        self.available_code_actions.take();
 6542    }
 6543
 6544    pub fn add_code_action_provider(
 6545        &mut self,
 6546        provider: Rc<dyn CodeActionProvider>,
 6547        window: &mut Window,
 6548        cx: &mut Context<Self>,
 6549    ) {
 6550        if self
 6551            .code_action_providers
 6552            .iter()
 6553            .any(|existing_provider| existing_provider.id() == provider.id())
 6554        {
 6555            return;
 6556        }
 6557
 6558        self.code_action_providers.push(provider);
 6559        self.refresh_code_actions(window, cx);
 6560    }
 6561
 6562    pub fn remove_code_action_provider(
 6563        &mut self,
 6564        id: Arc<str>,
 6565        window: &mut Window,
 6566        cx: &mut Context<Self>,
 6567    ) {
 6568        self.code_action_providers
 6569            .retain(|provider| provider.id() != id);
 6570        self.refresh_code_actions(window, cx);
 6571    }
 6572
 6573    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6574        !self.code_action_providers.is_empty()
 6575            && EditorSettings::get_global(cx).toolbar.code_actions
 6576    }
 6577
 6578    pub fn has_available_code_actions(&self) -> bool {
 6579        self.available_code_actions
 6580            .as_ref()
 6581            .is_some_and(|(_, actions)| !actions.is_empty())
 6582    }
 6583
 6584    fn render_inline_code_actions(
 6585        &self,
 6586        icon_size: ui::IconSize,
 6587        display_row: DisplayRow,
 6588        is_active: bool,
 6589        cx: &mut Context<Self>,
 6590    ) -> AnyElement {
 6591        let show_tooltip = !self.context_menu_visible();
 6592        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6593            .icon_size(icon_size)
 6594            .shape(ui::IconButtonShape::Square)
 6595            .icon_color(ui::Color::Hidden)
 6596            .toggle_state(is_active)
 6597            .when(show_tooltip, |this| {
 6598                this.tooltip({
 6599                    let focus_handle = self.focus_handle.clone();
 6600                    move |_window, cx| {
 6601                        Tooltip::for_action_in(
 6602                            "Toggle Code Actions",
 6603                            &ToggleCodeActions {
 6604                                deployed_from: None,
 6605                                quick_launch: false,
 6606                            },
 6607                            &focus_handle,
 6608                            cx,
 6609                        )
 6610                    }
 6611                })
 6612            })
 6613            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6614                window.focus(&editor.focus_handle(cx));
 6615                editor.toggle_code_actions(
 6616                    &crate::actions::ToggleCodeActions {
 6617                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6618                            display_row,
 6619                        )),
 6620                        quick_launch: false,
 6621                    },
 6622                    window,
 6623                    cx,
 6624                );
 6625            }))
 6626            .into_any_element()
 6627    }
 6628
 6629    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6630        &self.context_menu
 6631    }
 6632
 6633    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6634        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6635            cx.background_executor()
 6636                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6637                .await;
 6638
 6639            let (start_buffer, start, _, end, newest_selection) = this
 6640                .update(cx, |this, cx| {
 6641                    let newest_selection = this.selections.newest_anchor().clone();
 6642                    if newest_selection.head().diff_base_anchor.is_some() {
 6643                        return None;
 6644                    }
 6645                    let display_snapshot = this.display_snapshot(cx);
 6646                    let newest_selection_adjusted =
 6647                        this.selections.newest_adjusted(&display_snapshot);
 6648                    let buffer = this.buffer.read(cx);
 6649
 6650                    let (start_buffer, start) =
 6651                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6652                    let (end_buffer, end) =
 6653                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6654
 6655                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6656                })?
 6657                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6658                .context(
 6659                    "Expected selection to lie in a single buffer when refreshing code actions",
 6660                )?;
 6661            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6662                let providers = this.code_action_providers.clone();
 6663                let tasks = this
 6664                    .code_action_providers
 6665                    .iter()
 6666                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6667                    .collect::<Vec<_>>();
 6668                (providers, tasks)
 6669            })?;
 6670
 6671            let mut actions = Vec::new();
 6672            for (provider, provider_actions) in
 6673                providers.into_iter().zip(future::join_all(tasks).await)
 6674            {
 6675                if let Some(provider_actions) = provider_actions.log_err() {
 6676                    actions.extend(provider_actions.into_iter().map(|action| {
 6677                        AvailableCodeAction {
 6678                            excerpt_id: newest_selection.start.excerpt_id,
 6679                            action,
 6680                            provider: provider.clone(),
 6681                        }
 6682                    }));
 6683                }
 6684            }
 6685
 6686            this.update(cx, |this, cx| {
 6687                this.available_code_actions = if actions.is_empty() {
 6688                    None
 6689                } else {
 6690                    Some((
 6691                        Location {
 6692                            buffer: start_buffer,
 6693                            range: start..end,
 6694                        },
 6695                        actions.into(),
 6696                    ))
 6697                };
 6698                cx.notify();
 6699            })
 6700        }));
 6701    }
 6702
 6703    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6704        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6705            self.show_git_blame_inline = false;
 6706
 6707            self.show_git_blame_inline_delay_task =
 6708                Some(cx.spawn_in(window, async move |this, cx| {
 6709                    cx.background_executor().timer(delay).await;
 6710
 6711                    this.update(cx, |this, cx| {
 6712                        this.show_git_blame_inline = true;
 6713                        cx.notify();
 6714                    })
 6715                    .log_err();
 6716                }));
 6717        }
 6718    }
 6719
 6720    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6721        let snapshot = self.snapshot(window, cx);
 6722        let cursor = self
 6723            .selections
 6724            .newest::<Point>(&snapshot.display_snapshot)
 6725            .head();
 6726        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6727        else {
 6728            return;
 6729        };
 6730
 6731        let Some(blame) = self.blame.as_ref() else {
 6732            return;
 6733        };
 6734
 6735        let row_info = RowInfo {
 6736            buffer_id: Some(buffer.remote_id()),
 6737            buffer_row: Some(point.row),
 6738            ..Default::default()
 6739        };
 6740        let Some((buffer, blame_entry)) = blame
 6741            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6742            .flatten()
 6743        else {
 6744            return;
 6745        };
 6746
 6747        let anchor = self.selections.newest_anchor().head();
 6748        let position = self.to_pixel_point(anchor, &snapshot, window);
 6749        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6750            self.show_blame_popover(
 6751                buffer,
 6752                &blame_entry,
 6753                position + last_bounds.origin,
 6754                true,
 6755                cx,
 6756            );
 6757        };
 6758    }
 6759
 6760    fn show_blame_popover(
 6761        &mut self,
 6762        buffer: BufferId,
 6763        blame_entry: &BlameEntry,
 6764        position: gpui::Point<Pixels>,
 6765        ignore_timeout: bool,
 6766        cx: &mut Context<Self>,
 6767    ) {
 6768        if let Some(state) = &mut self.inline_blame_popover {
 6769            state.hide_task.take();
 6770        } else {
 6771            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6772            let blame_entry = blame_entry.clone();
 6773            let show_task = cx.spawn(async move |editor, cx| {
 6774                if !ignore_timeout {
 6775                    cx.background_executor()
 6776                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6777                        .await;
 6778                }
 6779                editor
 6780                    .update(cx, |editor, cx| {
 6781                        editor.inline_blame_popover_show_task.take();
 6782                        let Some(blame) = editor.blame.as_ref() else {
 6783                            return;
 6784                        };
 6785                        let blame = blame.read(cx);
 6786                        let details = blame.details_for_entry(buffer, &blame_entry);
 6787                        let markdown = cx.new(|cx| {
 6788                            Markdown::new(
 6789                                details
 6790                                    .as_ref()
 6791                                    .map(|message| message.message.clone())
 6792                                    .unwrap_or_default(),
 6793                                None,
 6794                                None,
 6795                                cx,
 6796                            )
 6797                        });
 6798                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6799                            position,
 6800                            hide_task: None,
 6801                            popover_bounds: None,
 6802                            popover_state: InlineBlamePopoverState {
 6803                                scroll_handle: ScrollHandle::new(),
 6804                                commit_message: details,
 6805                                markdown,
 6806                            },
 6807                            keyboard_grace: ignore_timeout,
 6808                        });
 6809                        cx.notify();
 6810                    })
 6811                    .ok();
 6812            });
 6813            self.inline_blame_popover_show_task = Some(show_task);
 6814        }
 6815    }
 6816
 6817    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6818        self.inline_blame_popover_show_task.take();
 6819        if let Some(state) = &mut self.inline_blame_popover {
 6820            let hide_task = cx.spawn(async move |editor, cx| {
 6821                if !ignore_timeout {
 6822                    cx.background_executor()
 6823                        .timer(std::time::Duration::from_millis(100))
 6824                        .await;
 6825                }
 6826                editor
 6827                    .update(cx, |editor, cx| {
 6828                        editor.inline_blame_popover.take();
 6829                        cx.notify();
 6830                    })
 6831                    .ok();
 6832            });
 6833            state.hide_task = Some(hide_task);
 6834            true
 6835        } else {
 6836            false
 6837        }
 6838    }
 6839
 6840    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6841        if self.pending_rename.is_some() {
 6842            return None;
 6843        }
 6844
 6845        let provider = self.semantics_provider.clone()?;
 6846        let buffer = self.buffer.read(cx);
 6847        let newest_selection = self.selections.newest_anchor().clone();
 6848        let cursor_position = newest_selection.head();
 6849        let (cursor_buffer, cursor_buffer_position) =
 6850            buffer.text_anchor_for_position(cursor_position, cx)?;
 6851        let (tail_buffer, tail_buffer_position) =
 6852            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6853        if cursor_buffer != tail_buffer {
 6854            return None;
 6855        }
 6856
 6857        let snapshot = cursor_buffer.read(cx).snapshot();
 6858        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6859        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6860        if start_word_range != end_word_range {
 6861            self.document_highlights_task.take();
 6862            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6863            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6864            return None;
 6865        }
 6866
 6867        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6868        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6869            cx.background_executor()
 6870                .timer(Duration::from_millis(debounce))
 6871                .await;
 6872
 6873            let highlights = if let Some(highlights) = cx
 6874                .update(|cx| {
 6875                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6876                })
 6877                .ok()
 6878                .flatten()
 6879            {
 6880                highlights.await.log_err()
 6881            } else {
 6882                None
 6883            };
 6884
 6885            if let Some(highlights) = highlights {
 6886                this.update(cx, |this, cx| {
 6887                    if this.pending_rename.is_some() {
 6888                        return;
 6889                    }
 6890
 6891                    let buffer = this.buffer.read(cx);
 6892                    if buffer
 6893                        .text_anchor_for_position(cursor_position, cx)
 6894                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6895                    {
 6896                        return;
 6897                    }
 6898
 6899                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6900                    let mut write_ranges = Vec::new();
 6901                    let mut read_ranges = Vec::new();
 6902                    for highlight in highlights {
 6903                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6904                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6905                        {
 6906                            let start = highlight
 6907                                .range
 6908                                .start
 6909                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6910                            let end = highlight
 6911                                .range
 6912                                .end
 6913                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6914                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6915                                continue;
 6916                            }
 6917
 6918                            let range =
 6919                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6920                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6921                                write_ranges.push(range);
 6922                            } else {
 6923                                read_ranges.push(range);
 6924                            }
 6925                        }
 6926                    }
 6927
 6928                    this.highlight_background::<DocumentHighlightRead>(
 6929                        &read_ranges,
 6930                        |theme| theme.colors().editor_document_highlight_read_background,
 6931                        cx,
 6932                    );
 6933                    this.highlight_background::<DocumentHighlightWrite>(
 6934                        &write_ranges,
 6935                        |theme| theme.colors().editor_document_highlight_write_background,
 6936                        cx,
 6937                    );
 6938                    cx.notify();
 6939                })
 6940                .log_err();
 6941            }
 6942        }));
 6943        None
 6944    }
 6945
 6946    fn prepare_highlight_query_from_selection(
 6947        &mut self,
 6948        window: &Window,
 6949        cx: &mut Context<Editor>,
 6950    ) -> Option<(String, Range<Anchor>)> {
 6951        if matches!(self.mode, EditorMode::SingleLine) {
 6952            return None;
 6953        }
 6954        if !EditorSettings::get_global(cx).selection_highlight {
 6955            return None;
 6956        }
 6957        if self.selections.count() != 1 || self.selections.line_mode() {
 6958            return None;
 6959        }
 6960        let snapshot = self.snapshot(window, cx);
 6961        let selection = self.selections.newest::<Point>(&snapshot);
 6962        // If the selection spans multiple rows OR it is empty
 6963        if selection.start.row != selection.end.row
 6964            || selection.start.column == selection.end.column
 6965        {
 6966            return None;
 6967        }
 6968        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6969        let query = snapshot
 6970            .buffer_snapshot()
 6971            .text_for_range(selection_anchor_range.clone())
 6972            .collect::<String>();
 6973        if query.trim().is_empty() {
 6974            return None;
 6975        }
 6976        Some((query, selection_anchor_range))
 6977    }
 6978
 6979    fn update_selection_occurrence_highlights(
 6980        &mut self,
 6981        query_text: String,
 6982        query_range: Range<Anchor>,
 6983        multi_buffer_range_to_query: Range<Point>,
 6984        use_debounce: bool,
 6985        window: &mut Window,
 6986        cx: &mut Context<Editor>,
 6987    ) -> Task<()> {
 6988        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6989        cx.spawn_in(window, async move |editor, cx| {
 6990            if use_debounce {
 6991                cx.background_executor()
 6992                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6993                    .await;
 6994            }
 6995            let match_task = cx.background_spawn(async move {
 6996                let buffer_ranges = multi_buffer_snapshot
 6997                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6998                    .into_iter()
 6999                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7000                let mut match_ranges = Vec::new();
 7001                let Ok(regex) = project::search::SearchQuery::text(
 7002                    query_text.clone(),
 7003                    false,
 7004                    false,
 7005                    false,
 7006                    Default::default(),
 7007                    Default::default(),
 7008                    false,
 7009                    None,
 7010                ) else {
 7011                    return Vec::default();
 7012                };
 7013                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7014                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7015                    match_ranges.extend(
 7016                        regex
 7017                            .search(
 7018                                buffer_snapshot,
 7019                                Some(search_range.start.0..search_range.end.0),
 7020                            )
 7021                            .await
 7022                            .into_iter()
 7023                            .filter_map(|match_range| {
 7024                                let match_start = buffer_snapshot
 7025                                    .anchor_after(search_range.start + match_range.start);
 7026                                let match_end = buffer_snapshot
 7027                                    .anchor_before(search_range.start + match_range.end);
 7028                                let match_anchor_range = Anchor::range_in_buffer(
 7029                                    excerpt_id,
 7030                                    buffer_snapshot.remote_id(),
 7031                                    match_start..match_end,
 7032                                );
 7033                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7034                            }),
 7035                    );
 7036                }
 7037                match_ranges
 7038            });
 7039            let match_ranges = match_task.await;
 7040            editor
 7041                .update_in(cx, |editor, _, cx| {
 7042                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7043                    if !match_ranges.is_empty() {
 7044                        editor.highlight_background::<SelectedTextHighlight>(
 7045                            &match_ranges,
 7046                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7047                            cx,
 7048                        )
 7049                    }
 7050                })
 7051                .log_err();
 7052        })
 7053    }
 7054
 7055    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7056        struct NewlineFold;
 7057        let type_id = std::any::TypeId::of::<NewlineFold>();
 7058        if !self.mode.is_single_line() {
 7059            return;
 7060        }
 7061        let snapshot = self.snapshot(window, cx);
 7062        if snapshot.buffer_snapshot().max_point().row == 0 {
 7063            return;
 7064        }
 7065        let task = cx.background_spawn(async move {
 7066            let new_newlines = snapshot
 7067                .buffer_chars_at(MultiBufferOffset(0))
 7068                .filter_map(|(c, i)| {
 7069                    if c == '\n' {
 7070                        Some(
 7071                            snapshot.buffer_snapshot().anchor_after(i)
 7072                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7073                        )
 7074                    } else {
 7075                        None
 7076                    }
 7077                })
 7078                .collect::<Vec<_>>();
 7079            let existing_newlines = snapshot
 7080                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7081                .filter_map(|fold| {
 7082                    if fold.placeholder.type_tag == Some(type_id) {
 7083                        Some(fold.range.start..fold.range.end)
 7084                    } else {
 7085                        None
 7086                    }
 7087                })
 7088                .collect::<Vec<_>>();
 7089
 7090            (new_newlines, existing_newlines)
 7091        });
 7092        self.folding_newlines = cx.spawn(async move |this, cx| {
 7093            let (new_newlines, existing_newlines) = task.await;
 7094            if new_newlines == existing_newlines {
 7095                return;
 7096            }
 7097            let placeholder = FoldPlaceholder {
 7098                render: Arc::new(move |_, _, cx| {
 7099                    div()
 7100                        .bg(cx.theme().status().hint_background)
 7101                        .border_b_1()
 7102                        .size_full()
 7103                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7104                        .border_color(cx.theme().status().hint)
 7105                        .child("\\n")
 7106                        .into_any()
 7107                }),
 7108                constrain_width: false,
 7109                merge_adjacent: false,
 7110                type_tag: Some(type_id),
 7111            };
 7112            let creases = new_newlines
 7113                .into_iter()
 7114                .map(|range| Crease::simple(range, placeholder.clone()))
 7115                .collect();
 7116            this.update(cx, |this, cx| {
 7117                this.display_map.update(cx, |display_map, cx| {
 7118                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7119                    display_map.fold(creases, cx);
 7120                });
 7121            })
 7122            .ok();
 7123        });
 7124    }
 7125
 7126    fn refresh_selected_text_highlights(
 7127        &mut self,
 7128        on_buffer_edit: bool,
 7129        window: &mut Window,
 7130        cx: &mut Context<Editor>,
 7131    ) {
 7132        let Some((query_text, query_range)) =
 7133            self.prepare_highlight_query_from_selection(window, cx)
 7134        else {
 7135            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7136            self.quick_selection_highlight_task.take();
 7137            self.debounced_selection_highlight_task.take();
 7138            return;
 7139        };
 7140        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7141        if on_buffer_edit
 7142            || self
 7143                .quick_selection_highlight_task
 7144                .as_ref()
 7145                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7146        {
 7147            let multi_buffer_visible_start = self
 7148                .scroll_manager
 7149                .anchor()
 7150                .anchor
 7151                .to_point(&multi_buffer_snapshot);
 7152            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7153                multi_buffer_visible_start
 7154                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7155                Bias::Left,
 7156            );
 7157            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7158            self.quick_selection_highlight_task = Some((
 7159                query_range.clone(),
 7160                self.update_selection_occurrence_highlights(
 7161                    query_text.clone(),
 7162                    query_range.clone(),
 7163                    multi_buffer_visible_range,
 7164                    false,
 7165                    window,
 7166                    cx,
 7167                ),
 7168            ));
 7169        }
 7170        if on_buffer_edit
 7171            || self
 7172                .debounced_selection_highlight_task
 7173                .as_ref()
 7174                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7175        {
 7176            let multi_buffer_start = multi_buffer_snapshot
 7177                .anchor_before(MultiBufferOffset(0))
 7178                .to_point(&multi_buffer_snapshot);
 7179            let multi_buffer_end = multi_buffer_snapshot
 7180                .anchor_after(multi_buffer_snapshot.len())
 7181                .to_point(&multi_buffer_snapshot);
 7182            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7183            self.debounced_selection_highlight_task = Some((
 7184                query_range.clone(),
 7185                self.update_selection_occurrence_highlights(
 7186                    query_text,
 7187                    query_range,
 7188                    multi_buffer_full_range,
 7189                    true,
 7190                    window,
 7191                    cx,
 7192                ),
 7193            ));
 7194        }
 7195    }
 7196
 7197    pub fn refresh_edit_prediction(
 7198        &mut self,
 7199        debounce: bool,
 7200        user_requested: bool,
 7201        window: &mut Window,
 7202        cx: &mut Context<Self>,
 7203    ) -> Option<()> {
 7204        if DisableAiSettings::get_global(cx).disable_ai {
 7205            return None;
 7206        }
 7207
 7208        let provider = self.edit_prediction_provider()?;
 7209        let cursor = self.selections.newest_anchor().head();
 7210        let (buffer, cursor_buffer_position) =
 7211            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7212
 7213        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7214            self.discard_edit_prediction(false, cx);
 7215            return None;
 7216        }
 7217
 7218        self.update_visible_edit_prediction(window, cx);
 7219
 7220        if !user_requested
 7221            && (!self.should_show_edit_predictions()
 7222                || !self.is_focused(window)
 7223                || buffer.read(cx).is_empty())
 7224        {
 7225            self.discard_edit_prediction(false, cx);
 7226            return None;
 7227        }
 7228
 7229        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7230        Some(())
 7231    }
 7232
 7233    fn show_edit_predictions_in_menu(&self) -> bool {
 7234        match self.edit_prediction_settings {
 7235            EditPredictionSettings::Disabled => false,
 7236            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7237        }
 7238    }
 7239
 7240    pub fn edit_predictions_enabled(&self) -> bool {
 7241        match self.edit_prediction_settings {
 7242            EditPredictionSettings::Disabled => false,
 7243            EditPredictionSettings::Enabled { .. } => true,
 7244        }
 7245    }
 7246
 7247    fn edit_prediction_requires_modifier(&self) -> bool {
 7248        match self.edit_prediction_settings {
 7249            EditPredictionSettings::Disabled => false,
 7250            EditPredictionSettings::Enabled {
 7251                preview_requires_modifier,
 7252                ..
 7253            } => preview_requires_modifier,
 7254        }
 7255    }
 7256
 7257    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7258        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7259            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7260            self.discard_edit_prediction(false, cx);
 7261        } else {
 7262            let selection = self.selections.newest_anchor();
 7263            let cursor = selection.head();
 7264
 7265            if let Some((buffer, cursor_buffer_position)) =
 7266                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7267            {
 7268                self.edit_prediction_settings =
 7269                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7270            }
 7271        }
 7272    }
 7273
 7274    fn edit_prediction_settings_at_position(
 7275        &self,
 7276        buffer: &Entity<Buffer>,
 7277        buffer_position: language::Anchor,
 7278        cx: &App,
 7279    ) -> EditPredictionSettings {
 7280        if !self.mode.is_full()
 7281            || !self.show_edit_predictions_override.unwrap_or(true)
 7282            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7283        {
 7284            return EditPredictionSettings::Disabled;
 7285        }
 7286
 7287        let buffer = buffer.read(cx);
 7288
 7289        let file = buffer.file();
 7290
 7291        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7292            return EditPredictionSettings::Disabled;
 7293        };
 7294
 7295        let by_provider = matches!(
 7296            self.menu_edit_predictions_policy,
 7297            MenuEditPredictionsPolicy::ByProvider
 7298        );
 7299
 7300        let show_in_menu = by_provider
 7301            && self
 7302                .edit_prediction_provider
 7303                .as_ref()
 7304                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7305
 7306        let preview_requires_modifier =
 7307            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7308
 7309        EditPredictionSettings::Enabled {
 7310            show_in_menu,
 7311            preview_requires_modifier,
 7312        }
 7313    }
 7314
 7315    fn should_show_edit_predictions(&self) -> bool {
 7316        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7317    }
 7318
 7319    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7320        matches!(
 7321            self.edit_prediction_preview,
 7322            EditPredictionPreview::Active { .. }
 7323        )
 7324    }
 7325
 7326    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7327        let cursor = self.selections.newest_anchor().head();
 7328        if let Some((buffer, cursor_position)) =
 7329            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7330        {
 7331            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7332        } else {
 7333            false
 7334        }
 7335    }
 7336
 7337    pub fn supports_minimap(&self, cx: &App) -> bool {
 7338        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7339    }
 7340
 7341    fn edit_predictions_enabled_in_buffer(
 7342        &self,
 7343        buffer: &Entity<Buffer>,
 7344        buffer_position: language::Anchor,
 7345        cx: &App,
 7346    ) -> bool {
 7347        maybe!({
 7348            if self.read_only(cx) {
 7349                return Some(false);
 7350            }
 7351            let provider = self.edit_prediction_provider()?;
 7352            if !provider.is_enabled(buffer, buffer_position, cx) {
 7353                return Some(false);
 7354            }
 7355            let buffer = buffer.read(cx);
 7356            let Some(file) = buffer.file() else {
 7357                return Some(true);
 7358            };
 7359            let settings = all_language_settings(Some(file), cx);
 7360            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7361        })
 7362        .unwrap_or(false)
 7363    }
 7364
 7365    fn cycle_edit_prediction(
 7366        &mut self,
 7367        direction: Direction,
 7368        window: &mut Window,
 7369        cx: &mut Context<Self>,
 7370    ) -> Option<()> {
 7371        let provider = self.edit_prediction_provider()?;
 7372        let cursor = self.selections.newest_anchor().head();
 7373        let (buffer, cursor_buffer_position) =
 7374            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7375        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7376            return None;
 7377        }
 7378
 7379        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7380        self.update_visible_edit_prediction(window, cx);
 7381
 7382        Some(())
 7383    }
 7384
 7385    pub fn show_edit_prediction(
 7386        &mut self,
 7387        _: &ShowEditPrediction,
 7388        window: &mut Window,
 7389        cx: &mut Context<Self>,
 7390    ) {
 7391        if !self.has_active_edit_prediction() {
 7392            self.refresh_edit_prediction(false, true, window, cx);
 7393            return;
 7394        }
 7395
 7396        self.update_visible_edit_prediction(window, cx);
 7397    }
 7398
 7399    pub fn display_cursor_names(
 7400        &mut self,
 7401        _: &DisplayCursorNames,
 7402        window: &mut Window,
 7403        cx: &mut Context<Self>,
 7404    ) {
 7405        self.show_cursor_names(window, cx);
 7406    }
 7407
 7408    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7409        self.show_cursor_names = true;
 7410        cx.notify();
 7411        cx.spawn_in(window, async move |this, cx| {
 7412            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7413            this.update(cx, |this, cx| {
 7414                this.show_cursor_names = false;
 7415                cx.notify()
 7416            })
 7417            .ok()
 7418        })
 7419        .detach();
 7420    }
 7421
 7422    pub fn next_edit_prediction(
 7423        &mut self,
 7424        _: &NextEditPrediction,
 7425        window: &mut Window,
 7426        cx: &mut Context<Self>,
 7427    ) {
 7428        if self.has_active_edit_prediction() {
 7429            self.cycle_edit_prediction(Direction::Next, window, cx);
 7430        } else {
 7431            let is_copilot_disabled = self
 7432                .refresh_edit_prediction(false, true, window, cx)
 7433                .is_none();
 7434            if is_copilot_disabled {
 7435                cx.propagate();
 7436            }
 7437        }
 7438    }
 7439
 7440    pub fn previous_edit_prediction(
 7441        &mut self,
 7442        _: &PreviousEditPrediction,
 7443        window: &mut Window,
 7444        cx: &mut Context<Self>,
 7445    ) {
 7446        if self.has_active_edit_prediction() {
 7447            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7448        } else {
 7449            let is_copilot_disabled = self
 7450                .refresh_edit_prediction(false, true, window, cx)
 7451                .is_none();
 7452            if is_copilot_disabled {
 7453                cx.propagate();
 7454            }
 7455        }
 7456    }
 7457
 7458    pub fn accept_edit_prediction(
 7459        &mut self,
 7460        _: &AcceptEditPrediction,
 7461        window: &mut Window,
 7462        cx: &mut Context<Self>,
 7463    ) {
 7464        if self.show_edit_predictions_in_menu() {
 7465            self.hide_context_menu(window, cx);
 7466        }
 7467
 7468        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7469            return;
 7470        };
 7471
 7472        match &active_edit_prediction.completion {
 7473            EditPrediction::MoveWithin { target, .. } => {
 7474                let target = *target;
 7475
 7476                if let Some(position_map) = &self.last_position_map {
 7477                    if position_map
 7478                        .visible_row_range
 7479                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7480                        || !self.edit_prediction_requires_modifier()
 7481                    {
 7482                        self.unfold_ranges(&[target..target], true, false, cx);
 7483                        // Note that this is also done in vim's handler of the Tab action.
 7484                        self.change_selections(
 7485                            SelectionEffects::scroll(Autoscroll::newest()),
 7486                            window,
 7487                            cx,
 7488                            |selections| {
 7489                                selections.select_anchor_ranges([target..target]);
 7490                            },
 7491                        );
 7492                        self.clear_row_highlights::<EditPredictionPreview>();
 7493
 7494                        self.edit_prediction_preview
 7495                            .set_previous_scroll_position(None);
 7496                    } else {
 7497                        self.edit_prediction_preview
 7498                            .set_previous_scroll_position(Some(
 7499                                position_map.snapshot.scroll_anchor,
 7500                            ));
 7501
 7502                        self.highlight_rows::<EditPredictionPreview>(
 7503                            target..target,
 7504                            cx.theme().colors().editor_highlighted_line_background,
 7505                            RowHighlightOptions {
 7506                                autoscroll: true,
 7507                                ..Default::default()
 7508                            },
 7509                            cx,
 7510                        );
 7511                        self.request_autoscroll(Autoscroll::fit(), cx);
 7512                    }
 7513                }
 7514            }
 7515            EditPrediction::MoveOutside { snapshot, target } => {
 7516                if let Some(workspace) = self.workspace() {
 7517                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7518                        .detach_and_log_err(cx);
 7519                }
 7520            }
 7521            EditPrediction::Edit { edits, .. } => {
 7522                self.report_edit_prediction_event(
 7523                    active_edit_prediction.completion_id.clone(),
 7524                    true,
 7525                    cx,
 7526                );
 7527
 7528                if let Some(provider) = self.edit_prediction_provider() {
 7529                    provider.accept(cx);
 7530                }
 7531
 7532                // Store the transaction ID and selections before applying the edit
 7533                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7534
 7535                let snapshot = self.buffer.read(cx).snapshot(cx);
 7536                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7537
 7538                self.buffer.update(cx, |buffer, cx| {
 7539                    buffer.edit(edits.iter().cloned(), None, cx)
 7540                });
 7541
 7542                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7543                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7544                });
 7545
 7546                let selections = self.selections.disjoint_anchors_arc();
 7547                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7548                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7549                    if has_new_transaction {
 7550                        self.selection_history
 7551                            .insert_transaction(transaction_id_now, selections);
 7552                    }
 7553                }
 7554
 7555                self.update_visible_edit_prediction(window, cx);
 7556                if self.active_edit_prediction.is_none() {
 7557                    self.refresh_edit_prediction(true, true, window, cx);
 7558                }
 7559
 7560                cx.notify();
 7561            }
 7562        }
 7563
 7564        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7565    }
 7566
 7567    pub fn accept_partial_edit_prediction(
 7568        &mut self,
 7569        _: &AcceptPartialEditPrediction,
 7570        window: &mut Window,
 7571        cx: &mut Context<Self>,
 7572    ) {
 7573        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7574            return;
 7575        };
 7576        if self.selections.count() != 1 {
 7577            return;
 7578        }
 7579
 7580        match &active_edit_prediction.completion {
 7581            EditPrediction::MoveWithin { target, .. } => {
 7582                let target = *target;
 7583                self.change_selections(
 7584                    SelectionEffects::scroll(Autoscroll::newest()),
 7585                    window,
 7586                    cx,
 7587                    |selections| {
 7588                        selections.select_anchor_ranges([target..target]);
 7589                    },
 7590                );
 7591            }
 7592            EditPrediction::MoveOutside { snapshot, target } => {
 7593                if let Some(workspace) = self.workspace() {
 7594                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7595                        .detach_and_log_err(cx);
 7596                }
 7597            }
 7598            EditPrediction::Edit { edits, .. } => {
 7599                self.report_edit_prediction_event(
 7600                    active_edit_prediction.completion_id.clone(),
 7601                    true,
 7602                    cx,
 7603                );
 7604
 7605                // Find an insertion that starts at the cursor position.
 7606                let snapshot = self.buffer.read(cx).snapshot(cx);
 7607                let cursor_offset = self
 7608                    .selections
 7609                    .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7610                    .head();
 7611                let insertion = edits.iter().find_map(|(range, text)| {
 7612                    let range = range.to_offset(&snapshot);
 7613                    if range.is_empty() && range.start == cursor_offset {
 7614                        Some(text)
 7615                    } else {
 7616                        None
 7617                    }
 7618                });
 7619
 7620                if let Some(text) = insertion {
 7621                    let mut partial_completion = text
 7622                        .chars()
 7623                        .by_ref()
 7624                        .take_while(|c| c.is_alphabetic())
 7625                        .collect::<String>();
 7626                    if partial_completion.is_empty() {
 7627                        partial_completion = text
 7628                            .chars()
 7629                            .by_ref()
 7630                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7631                            .collect::<String>();
 7632                    }
 7633
 7634                    cx.emit(EditorEvent::InputHandled {
 7635                        utf16_range_to_replace: None,
 7636                        text: partial_completion.clone().into(),
 7637                    });
 7638
 7639                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7640
 7641                    self.refresh_edit_prediction(true, true, window, cx);
 7642                    cx.notify();
 7643                } else {
 7644                    self.accept_edit_prediction(&Default::default(), window, cx);
 7645                }
 7646            }
 7647        }
 7648    }
 7649
 7650    fn discard_edit_prediction(
 7651        &mut self,
 7652        should_report_edit_prediction_event: bool,
 7653        cx: &mut Context<Self>,
 7654    ) -> bool {
 7655        if should_report_edit_prediction_event {
 7656            let completion_id = self
 7657                .active_edit_prediction
 7658                .as_ref()
 7659                .and_then(|active_completion| active_completion.completion_id.clone());
 7660
 7661            self.report_edit_prediction_event(completion_id, false, cx);
 7662        }
 7663
 7664        if let Some(provider) = self.edit_prediction_provider() {
 7665            provider.discard(cx);
 7666        }
 7667
 7668        self.take_active_edit_prediction(cx)
 7669    }
 7670
 7671    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7672        let Some(provider) = self.edit_prediction_provider() else {
 7673            return;
 7674        };
 7675
 7676        let Some((_, buffer, _)) = self
 7677            .buffer
 7678            .read(cx)
 7679            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7680        else {
 7681            return;
 7682        };
 7683
 7684        let extension = buffer
 7685            .read(cx)
 7686            .file()
 7687            .and_then(|file| Some(file.path().extension()?.to_string()));
 7688
 7689        let event_type = match accepted {
 7690            true => "Edit Prediction Accepted",
 7691            false => "Edit Prediction Discarded",
 7692        };
 7693        telemetry::event!(
 7694            event_type,
 7695            provider = provider.name(),
 7696            prediction_id = id,
 7697            suggestion_accepted = accepted,
 7698            file_extension = extension,
 7699        );
 7700    }
 7701
 7702    fn open_editor_at_anchor(
 7703        snapshot: &language::BufferSnapshot,
 7704        target: language::Anchor,
 7705        workspace: &Entity<Workspace>,
 7706        window: &mut Window,
 7707        cx: &mut App,
 7708    ) -> Task<Result<()>> {
 7709        workspace.update(cx, |workspace, cx| {
 7710            let path = snapshot.file().map(|file| file.full_path(cx));
 7711            let Some(path) =
 7712                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7713            else {
 7714                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7715            };
 7716            let target = text::ToPoint::to_point(&target, snapshot);
 7717            let item = workspace.open_path(path, None, true, window, cx);
 7718            window.spawn(cx, async move |cx| {
 7719                let Some(editor) = item.await?.downcast::<Editor>() else {
 7720                    return Ok(());
 7721                };
 7722                editor
 7723                    .update_in(cx, |editor, window, cx| {
 7724                        editor.go_to_singleton_buffer_point(target, window, cx);
 7725                    })
 7726                    .ok();
 7727                anyhow::Ok(())
 7728            })
 7729        })
 7730    }
 7731
 7732    pub fn has_active_edit_prediction(&self) -> bool {
 7733        self.active_edit_prediction.is_some()
 7734    }
 7735
 7736    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7737        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7738            return false;
 7739        };
 7740
 7741        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7742        self.clear_highlights::<EditPredictionHighlight>(cx);
 7743        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7744        true
 7745    }
 7746
 7747    /// Returns true when we're displaying the edit prediction popover below the cursor
 7748    /// like we are not previewing and the LSP autocomplete menu is visible
 7749    /// or we are in `when_holding_modifier` mode.
 7750    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7751        if self.edit_prediction_preview_is_active()
 7752            || !self.show_edit_predictions_in_menu()
 7753            || !self.edit_predictions_enabled()
 7754        {
 7755            return false;
 7756        }
 7757
 7758        if self.has_visible_completions_menu() {
 7759            return true;
 7760        }
 7761
 7762        has_completion && self.edit_prediction_requires_modifier()
 7763    }
 7764
 7765    fn handle_modifiers_changed(
 7766        &mut self,
 7767        modifiers: Modifiers,
 7768        position_map: &PositionMap,
 7769        window: &mut Window,
 7770        cx: &mut Context<Self>,
 7771    ) {
 7772        // Ensure that the edit prediction preview is updated, even when not
 7773        // enabled, if there's an active edit prediction preview.
 7774        if self.show_edit_predictions_in_menu()
 7775            || matches!(
 7776                self.edit_prediction_preview,
 7777                EditPredictionPreview::Active { .. }
 7778            )
 7779        {
 7780            self.update_edit_prediction_preview(&modifiers, window, cx);
 7781        }
 7782
 7783        self.update_selection_mode(&modifiers, position_map, window, cx);
 7784
 7785        let mouse_position = window.mouse_position();
 7786        if !position_map.text_hitbox.is_hovered(window) {
 7787            return;
 7788        }
 7789
 7790        self.update_hovered_link(
 7791            position_map.point_for_position(mouse_position),
 7792            &position_map.snapshot,
 7793            modifiers,
 7794            window,
 7795            cx,
 7796        )
 7797    }
 7798
 7799    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7800        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7801            MultiCursorModifier::Alt => modifiers.secondary(),
 7802            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7803        }
 7804    }
 7805
 7806    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7807        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7808            MultiCursorModifier::Alt => modifiers.alt,
 7809            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7810        }
 7811    }
 7812
 7813    fn columnar_selection_mode(
 7814        modifiers: &Modifiers,
 7815        cx: &mut Context<Self>,
 7816    ) -> Option<ColumnarMode> {
 7817        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7818            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7819                Some(ColumnarMode::FromMouse)
 7820            } else if Self::is_alt_pressed(modifiers, cx) {
 7821                Some(ColumnarMode::FromSelection)
 7822            } else {
 7823                None
 7824            }
 7825        } else {
 7826            None
 7827        }
 7828    }
 7829
 7830    fn update_selection_mode(
 7831        &mut self,
 7832        modifiers: &Modifiers,
 7833        position_map: &PositionMap,
 7834        window: &mut Window,
 7835        cx: &mut Context<Self>,
 7836    ) {
 7837        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7838            return;
 7839        };
 7840        if self.selections.pending_anchor().is_none() {
 7841            return;
 7842        }
 7843
 7844        let mouse_position = window.mouse_position();
 7845        let point_for_position = position_map.point_for_position(mouse_position);
 7846        let position = point_for_position.previous_valid;
 7847
 7848        self.select(
 7849            SelectPhase::BeginColumnar {
 7850                position,
 7851                reset: false,
 7852                mode,
 7853                goal_column: point_for_position.exact_unclipped.column(),
 7854            },
 7855            window,
 7856            cx,
 7857        );
 7858    }
 7859
 7860    fn update_edit_prediction_preview(
 7861        &mut self,
 7862        modifiers: &Modifiers,
 7863        window: &mut Window,
 7864        cx: &mut Context<Self>,
 7865    ) {
 7866        let mut modifiers_held = false;
 7867        if let Some(accept_keystroke) = self
 7868            .accept_edit_prediction_keybind(false, window, cx)
 7869            .keystroke()
 7870        {
 7871            modifiers_held = modifiers_held
 7872                || (accept_keystroke.modifiers() == modifiers
 7873                    && accept_keystroke.modifiers().modified());
 7874        };
 7875        if let Some(accept_partial_keystroke) = self
 7876            .accept_edit_prediction_keybind(true, window, cx)
 7877            .keystroke()
 7878        {
 7879            modifiers_held = modifiers_held
 7880                || (accept_partial_keystroke.modifiers() == modifiers
 7881                    && accept_partial_keystroke.modifiers().modified());
 7882        }
 7883
 7884        if modifiers_held {
 7885            if matches!(
 7886                self.edit_prediction_preview,
 7887                EditPredictionPreview::Inactive { .. }
 7888            ) {
 7889                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 7890                    provider.provider.did_show(cx)
 7891                }
 7892
 7893                self.edit_prediction_preview = EditPredictionPreview::Active {
 7894                    previous_scroll_position: None,
 7895                    since: Instant::now(),
 7896                };
 7897
 7898                self.update_visible_edit_prediction(window, cx);
 7899                cx.notify();
 7900            }
 7901        } else if let EditPredictionPreview::Active {
 7902            previous_scroll_position,
 7903            since,
 7904        } = self.edit_prediction_preview
 7905        {
 7906            if let (Some(previous_scroll_position), Some(position_map)) =
 7907                (previous_scroll_position, self.last_position_map.as_ref())
 7908            {
 7909                self.set_scroll_position(
 7910                    previous_scroll_position
 7911                        .scroll_position(&position_map.snapshot.display_snapshot),
 7912                    window,
 7913                    cx,
 7914                );
 7915            }
 7916
 7917            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7918                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7919            };
 7920            self.clear_row_highlights::<EditPredictionPreview>();
 7921            self.update_visible_edit_prediction(window, cx);
 7922            cx.notify();
 7923        }
 7924    }
 7925
 7926    fn update_visible_edit_prediction(
 7927        &mut self,
 7928        _window: &mut Window,
 7929        cx: &mut Context<Self>,
 7930    ) -> Option<()> {
 7931        if DisableAiSettings::get_global(cx).disable_ai {
 7932            return None;
 7933        }
 7934
 7935        if self.ime_transaction.is_some() {
 7936            self.discard_edit_prediction(false, cx);
 7937            return None;
 7938        }
 7939
 7940        let selection = self.selections.newest_anchor();
 7941        let cursor = selection.head();
 7942        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7943        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7944        let excerpt_id = cursor.excerpt_id;
 7945
 7946        let show_in_menu = self.show_edit_predictions_in_menu();
 7947        let completions_menu_has_precedence = !show_in_menu
 7948            && (self.context_menu.borrow().is_some()
 7949                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7950
 7951        if completions_menu_has_precedence
 7952            || !offset_selection.is_empty()
 7953            || self
 7954                .active_edit_prediction
 7955                .as_ref()
 7956                .is_some_and(|completion| {
 7957                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7958                        return false;
 7959                    };
 7960                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7961                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7962                    !invalidation_range.contains(&offset_selection.head())
 7963                })
 7964        {
 7965            self.discard_edit_prediction(false, cx);
 7966            return None;
 7967        }
 7968
 7969        self.take_active_edit_prediction(cx);
 7970        let Some(provider) = self.edit_prediction_provider() else {
 7971            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7972            return None;
 7973        };
 7974
 7975        let (buffer, cursor_buffer_position) =
 7976            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7977
 7978        self.edit_prediction_settings =
 7979            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7980
 7981        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7982
 7983        if self.edit_prediction_indent_conflict {
 7984            let cursor_point = cursor.to_point(&multibuffer);
 7985
 7986            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7987
 7988            if let Some((_, indent)) = indents.iter().next()
 7989                && indent.len == cursor_point.column
 7990            {
 7991                self.edit_prediction_indent_conflict = false;
 7992            }
 7993        }
 7994
 7995        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7996
 7997        let (completion_id, edits, edit_preview) = match edit_prediction {
 7998            edit_prediction::EditPrediction::Local {
 7999                id,
 8000                edits,
 8001                edit_preview,
 8002            } => (id, edits, edit_preview),
 8003            edit_prediction::EditPrediction::Jump {
 8004                id,
 8005                snapshot,
 8006                target,
 8007            } => {
 8008                self.stale_edit_prediction_in_menu = None;
 8009                self.active_edit_prediction = Some(EditPredictionState {
 8010                    inlay_ids: vec![],
 8011                    completion: EditPrediction::MoveOutside { snapshot, target },
 8012                    completion_id: id,
 8013                    invalidation_range: None,
 8014                });
 8015                cx.notify();
 8016                return Some(());
 8017            }
 8018        };
 8019
 8020        let edits = edits
 8021            .into_iter()
 8022            .flat_map(|(range, new_text)| {
 8023                Some((
 8024                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8025                    new_text,
 8026                ))
 8027            })
 8028            .collect::<Vec<_>>();
 8029        if edits.is_empty() {
 8030            return None;
 8031        }
 8032
 8033        let first_edit_start = edits.first().unwrap().0.start;
 8034        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8035        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8036
 8037        let last_edit_end = edits.last().unwrap().0.end;
 8038        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8039        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8040
 8041        let cursor_row = cursor.to_point(&multibuffer).row;
 8042
 8043        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8044
 8045        let mut inlay_ids = Vec::new();
 8046        let invalidation_row_range;
 8047        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8048            Some(cursor_row..edit_end_row)
 8049        } else if cursor_row > edit_end_row {
 8050            Some(edit_start_row..cursor_row)
 8051        } else {
 8052            None
 8053        };
 8054        let supports_jump = self
 8055            .edit_prediction_provider
 8056            .as_ref()
 8057            .map(|provider| provider.provider.supports_jump_to_edit())
 8058            .unwrap_or(true);
 8059
 8060        let is_move = supports_jump
 8061            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8062        let completion = if is_move {
 8063            invalidation_row_range =
 8064                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8065            let target = first_edit_start;
 8066            EditPrediction::MoveWithin { target, snapshot }
 8067        } else {
 8068            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8069                && !self.edit_predictions_hidden_for_vim_mode;
 8070
 8071            if show_completions_in_buffer {
 8072                if let Some(provider) = &self.edit_prediction_provider {
 8073                    provider.provider.did_show(cx);
 8074                }
 8075                if edits
 8076                    .iter()
 8077                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8078                {
 8079                    let mut inlays = Vec::new();
 8080                    for (range, new_text) in &edits {
 8081                        let inlay = Inlay::edit_prediction(
 8082                            post_inc(&mut self.next_inlay_id),
 8083                            range.start,
 8084                            new_text.as_ref(),
 8085                        );
 8086                        inlay_ids.push(inlay.id);
 8087                        inlays.push(inlay);
 8088                    }
 8089
 8090                    self.splice_inlays(&[], inlays, cx);
 8091                } else {
 8092                    let background_color = cx.theme().status().deleted_background;
 8093                    self.highlight_text::<EditPredictionHighlight>(
 8094                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8095                        HighlightStyle {
 8096                            background_color: Some(background_color),
 8097                            ..Default::default()
 8098                        },
 8099                        cx,
 8100                    );
 8101                }
 8102            }
 8103
 8104            invalidation_row_range = edit_start_row..edit_end_row;
 8105
 8106            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8107                if provider.show_tab_accept_marker() {
 8108                    EditDisplayMode::TabAccept
 8109                } else {
 8110                    EditDisplayMode::Inline
 8111                }
 8112            } else {
 8113                EditDisplayMode::DiffPopover
 8114            };
 8115
 8116            EditPrediction::Edit {
 8117                edits,
 8118                edit_preview,
 8119                display_mode,
 8120                snapshot,
 8121            }
 8122        };
 8123
 8124        let invalidation_range = multibuffer
 8125            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8126            ..multibuffer.anchor_after(Point::new(
 8127                invalidation_row_range.end,
 8128                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8129            ));
 8130
 8131        self.stale_edit_prediction_in_menu = None;
 8132        self.active_edit_prediction = Some(EditPredictionState {
 8133            inlay_ids,
 8134            completion,
 8135            completion_id,
 8136            invalidation_range: Some(invalidation_range),
 8137        });
 8138
 8139        cx.notify();
 8140
 8141        Some(())
 8142    }
 8143
 8144    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8145        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8146    }
 8147
 8148    fn clear_tasks(&mut self) {
 8149        self.tasks.clear()
 8150    }
 8151
 8152    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8153        if self.tasks.insert(key, value).is_some() {
 8154            // This case should hopefully be rare, but just in case...
 8155            log::error!(
 8156                "multiple different run targets found on a single line, only the last target will be rendered"
 8157            )
 8158        }
 8159    }
 8160
 8161    /// Get all display points of breakpoints that will be rendered within editor
 8162    ///
 8163    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8164    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8165    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8166    fn active_breakpoints(
 8167        &self,
 8168        range: Range<DisplayRow>,
 8169        window: &mut Window,
 8170        cx: &mut Context<Self>,
 8171    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8172        let mut breakpoint_display_points = HashMap::default();
 8173
 8174        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8175            return breakpoint_display_points;
 8176        };
 8177
 8178        let snapshot = self.snapshot(window, cx);
 8179
 8180        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8181        let Some(project) = self.project() else {
 8182            return breakpoint_display_points;
 8183        };
 8184
 8185        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8186            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8187
 8188        for (buffer_snapshot, range, excerpt_id) in
 8189            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8190        {
 8191            let Some(buffer) = project
 8192                .read(cx)
 8193                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8194            else {
 8195                continue;
 8196            };
 8197            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8198                &buffer,
 8199                Some(
 8200                    buffer_snapshot.anchor_before(range.start)
 8201                        ..buffer_snapshot.anchor_after(range.end),
 8202                ),
 8203                buffer_snapshot,
 8204                cx,
 8205            );
 8206            for (breakpoint, state) in breakpoints {
 8207                let multi_buffer_anchor =
 8208                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8209                let position = multi_buffer_anchor
 8210                    .to_point(&multi_buffer_snapshot)
 8211                    .to_display_point(&snapshot);
 8212
 8213                breakpoint_display_points.insert(
 8214                    position.row(),
 8215                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8216                );
 8217            }
 8218        }
 8219
 8220        breakpoint_display_points
 8221    }
 8222
 8223    fn breakpoint_context_menu(
 8224        &self,
 8225        anchor: Anchor,
 8226        window: &mut Window,
 8227        cx: &mut Context<Self>,
 8228    ) -> Entity<ui::ContextMenu> {
 8229        let weak_editor = cx.weak_entity();
 8230        let focus_handle = self.focus_handle(cx);
 8231
 8232        let row = self
 8233            .buffer
 8234            .read(cx)
 8235            .snapshot(cx)
 8236            .summary_for_anchor::<Point>(&anchor)
 8237            .row;
 8238
 8239        let breakpoint = self
 8240            .breakpoint_at_row(row, window, cx)
 8241            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8242
 8243        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8244            "Edit Log Breakpoint"
 8245        } else {
 8246            "Set Log Breakpoint"
 8247        };
 8248
 8249        let condition_breakpoint_msg = if breakpoint
 8250            .as_ref()
 8251            .is_some_and(|bp| bp.1.condition.is_some())
 8252        {
 8253            "Edit Condition Breakpoint"
 8254        } else {
 8255            "Set Condition Breakpoint"
 8256        };
 8257
 8258        let hit_condition_breakpoint_msg = if breakpoint
 8259            .as_ref()
 8260            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8261        {
 8262            "Edit Hit Condition Breakpoint"
 8263        } else {
 8264            "Set Hit Condition Breakpoint"
 8265        };
 8266
 8267        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8268            "Unset Breakpoint"
 8269        } else {
 8270            "Set Breakpoint"
 8271        };
 8272
 8273        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8274
 8275        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8276            BreakpointState::Enabled => Some("Disable"),
 8277            BreakpointState::Disabled => Some("Enable"),
 8278        });
 8279
 8280        let (anchor, breakpoint) =
 8281            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8282
 8283        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8284            menu.on_blur_subscription(Subscription::new(|| {}))
 8285                .context(focus_handle)
 8286                .when(run_to_cursor, |this| {
 8287                    let weak_editor = weak_editor.clone();
 8288                    this.entry("Run to cursor", None, move |window, cx| {
 8289                        weak_editor
 8290                            .update(cx, |editor, cx| {
 8291                                editor.change_selections(
 8292                                    SelectionEffects::no_scroll(),
 8293                                    window,
 8294                                    cx,
 8295                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8296                                );
 8297                            })
 8298                            .ok();
 8299
 8300                        window.dispatch_action(Box::new(RunToCursor), cx);
 8301                    })
 8302                    .separator()
 8303                })
 8304                .when_some(toggle_state_msg, |this, msg| {
 8305                    this.entry(msg, None, {
 8306                        let weak_editor = weak_editor.clone();
 8307                        let breakpoint = breakpoint.clone();
 8308                        move |_window, cx| {
 8309                            weak_editor
 8310                                .update(cx, |this, cx| {
 8311                                    this.edit_breakpoint_at_anchor(
 8312                                        anchor,
 8313                                        breakpoint.as_ref().clone(),
 8314                                        BreakpointEditAction::InvertState,
 8315                                        cx,
 8316                                    );
 8317                                })
 8318                                .log_err();
 8319                        }
 8320                    })
 8321                })
 8322                .entry(set_breakpoint_msg, None, {
 8323                    let weak_editor = weak_editor.clone();
 8324                    let breakpoint = breakpoint.clone();
 8325                    move |_window, cx| {
 8326                        weak_editor
 8327                            .update(cx, |this, cx| {
 8328                                this.edit_breakpoint_at_anchor(
 8329                                    anchor,
 8330                                    breakpoint.as_ref().clone(),
 8331                                    BreakpointEditAction::Toggle,
 8332                                    cx,
 8333                                );
 8334                            })
 8335                            .log_err();
 8336                    }
 8337                })
 8338                .entry(log_breakpoint_msg, None, {
 8339                    let breakpoint = breakpoint.clone();
 8340                    let weak_editor = weak_editor.clone();
 8341                    move |window, cx| {
 8342                        weak_editor
 8343                            .update(cx, |this, cx| {
 8344                                this.add_edit_breakpoint_block(
 8345                                    anchor,
 8346                                    breakpoint.as_ref(),
 8347                                    BreakpointPromptEditAction::Log,
 8348                                    window,
 8349                                    cx,
 8350                                );
 8351                            })
 8352                            .log_err();
 8353                    }
 8354                })
 8355                .entry(condition_breakpoint_msg, None, {
 8356                    let breakpoint = breakpoint.clone();
 8357                    let weak_editor = weak_editor.clone();
 8358                    move |window, cx| {
 8359                        weak_editor
 8360                            .update(cx, |this, cx| {
 8361                                this.add_edit_breakpoint_block(
 8362                                    anchor,
 8363                                    breakpoint.as_ref(),
 8364                                    BreakpointPromptEditAction::Condition,
 8365                                    window,
 8366                                    cx,
 8367                                );
 8368                            })
 8369                            .log_err();
 8370                    }
 8371                })
 8372                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8373                    weak_editor
 8374                        .update(cx, |this, cx| {
 8375                            this.add_edit_breakpoint_block(
 8376                                anchor,
 8377                                breakpoint.as_ref(),
 8378                                BreakpointPromptEditAction::HitCondition,
 8379                                window,
 8380                                cx,
 8381                            );
 8382                        })
 8383                        .log_err();
 8384                })
 8385        })
 8386    }
 8387
 8388    fn render_breakpoint(
 8389        &self,
 8390        position: Anchor,
 8391        row: DisplayRow,
 8392        breakpoint: &Breakpoint,
 8393        state: Option<BreakpointSessionState>,
 8394        cx: &mut Context<Self>,
 8395    ) -> IconButton {
 8396        let is_rejected = state.is_some_and(|s| !s.verified);
 8397        // Is it a breakpoint that shows up when hovering over gutter?
 8398        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8399            (false, false),
 8400            |PhantomBreakpointIndicator {
 8401                 is_active,
 8402                 display_row,
 8403                 collides_with_existing_breakpoint,
 8404             }| {
 8405                (
 8406                    is_active && display_row == row,
 8407                    collides_with_existing_breakpoint,
 8408                )
 8409            },
 8410        );
 8411
 8412        let (color, icon) = {
 8413            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8414                (false, false) => ui::IconName::DebugBreakpoint,
 8415                (true, false) => ui::IconName::DebugLogBreakpoint,
 8416                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8417                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8418            };
 8419
 8420            let color = if is_phantom {
 8421                Color::Hint
 8422            } else if is_rejected {
 8423                Color::Disabled
 8424            } else {
 8425                Color::Debugger
 8426            };
 8427
 8428            (color, icon)
 8429        };
 8430
 8431        let breakpoint = Arc::from(breakpoint.clone());
 8432
 8433        let alt_as_text = gpui::Keystroke {
 8434            modifiers: Modifiers::secondary_key(),
 8435            ..Default::default()
 8436        };
 8437        let primary_action_text = if breakpoint.is_disabled() {
 8438            "Enable breakpoint"
 8439        } else if is_phantom && !collides_with_existing {
 8440            "Set breakpoint"
 8441        } else {
 8442            "Unset breakpoint"
 8443        };
 8444        let focus_handle = self.focus_handle.clone();
 8445
 8446        let meta = if is_rejected {
 8447            SharedString::from("No executable code is associated with this line.")
 8448        } else if collides_with_existing && !breakpoint.is_disabled() {
 8449            SharedString::from(format!(
 8450                "{alt_as_text}-click to disable,\nright-click for more options."
 8451            ))
 8452        } else {
 8453            SharedString::from("Right-click for more options.")
 8454        };
 8455        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8456            .icon_size(IconSize::XSmall)
 8457            .size(ui::ButtonSize::None)
 8458            .when(is_rejected, |this| {
 8459                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8460            })
 8461            .icon_color(color)
 8462            .style(ButtonStyle::Transparent)
 8463            .on_click(cx.listener({
 8464                move |editor, event: &ClickEvent, window, cx| {
 8465                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8466                        BreakpointEditAction::InvertState
 8467                    } else {
 8468                        BreakpointEditAction::Toggle
 8469                    };
 8470
 8471                    window.focus(&editor.focus_handle(cx));
 8472                    editor.edit_breakpoint_at_anchor(
 8473                        position,
 8474                        breakpoint.as_ref().clone(),
 8475                        edit_action,
 8476                        cx,
 8477                    );
 8478                }
 8479            }))
 8480            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8481                editor.set_breakpoint_context_menu(
 8482                    row,
 8483                    Some(position),
 8484                    event.position(),
 8485                    window,
 8486                    cx,
 8487                );
 8488            }))
 8489            .tooltip(move |_window, cx| {
 8490                Tooltip::with_meta_in(
 8491                    primary_action_text,
 8492                    Some(&ToggleBreakpoint),
 8493                    meta.clone(),
 8494                    &focus_handle,
 8495                    cx,
 8496                )
 8497            })
 8498    }
 8499
 8500    fn build_tasks_context(
 8501        project: &Entity<Project>,
 8502        buffer: &Entity<Buffer>,
 8503        buffer_row: u32,
 8504        tasks: &Arc<RunnableTasks>,
 8505        cx: &mut Context<Self>,
 8506    ) -> Task<Option<task::TaskContext>> {
 8507        let position = Point::new(buffer_row, tasks.column);
 8508        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8509        let location = Location {
 8510            buffer: buffer.clone(),
 8511            range: range_start..range_start,
 8512        };
 8513        // Fill in the environmental variables from the tree-sitter captures
 8514        let mut captured_task_variables = TaskVariables::default();
 8515        for (capture_name, value) in tasks.extra_variables.clone() {
 8516            captured_task_variables.insert(
 8517                task::VariableName::Custom(capture_name.into()),
 8518                value.clone(),
 8519            );
 8520        }
 8521        project.update(cx, |project, cx| {
 8522            project.task_store().update(cx, |task_store, cx| {
 8523                task_store.task_context_for_location(captured_task_variables, location, cx)
 8524            })
 8525        })
 8526    }
 8527
 8528    pub fn spawn_nearest_task(
 8529        &mut self,
 8530        action: &SpawnNearestTask,
 8531        window: &mut Window,
 8532        cx: &mut Context<Self>,
 8533    ) {
 8534        let Some((workspace, _)) = self.workspace.clone() else {
 8535            return;
 8536        };
 8537        let Some(project) = self.project.clone() else {
 8538            return;
 8539        };
 8540
 8541        // Try to find a closest, enclosing node using tree-sitter that has a task
 8542        let Some((buffer, buffer_row, tasks)) = self
 8543            .find_enclosing_node_task(cx)
 8544            // Or find the task that's closest in row-distance.
 8545            .or_else(|| self.find_closest_task(cx))
 8546        else {
 8547            return;
 8548        };
 8549
 8550        let reveal_strategy = action.reveal;
 8551        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8552        cx.spawn_in(window, async move |_, cx| {
 8553            let context = task_context.await?;
 8554            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8555
 8556            let resolved = &mut resolved_task.resolved;
 8557            resolved.reveal = reveal_strategy;
 8558
 8559            workspace
 8560                .update_in(cx, |workspace, window, cx| {
 8561                    workspace.schedule_resolved_task(
 8562                        task_source_kind,
 8563                        resolved_task,
 8564                        false,
 8565                        window,
 8566                        cx,
 8567                    );
 8568                })
 8569                .ok()
 8570        })
 8571        .detach();
 8572    }
 8573
 8574    fn find_closest_task(
 8575        &mut self,
 8576        cx: &mut Context<Self>,
 8577    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8578        let cursor_row = self
 8579            .selections
 8580            .newest_adjusted(&self.display_snapshot(cx))
 8581            .head()
 8582            .row;
 8583
 8584        let ((buffer_id, row), tasks) = self
 8585            .tasks
 8586            .iter()
 8587            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8588
 8589        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8590        let tasks = Arc::new(tasks.to_owned());
 8591        Some((buffer, *row, tasks))
 8592    }
 8593
 8594    fn find_enclosing_node_task(
 8595        &mut self,
 8596        cx: &mut Context<Self>,
 8597    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8598        let snapshot = self.buffer.read(cx).snapshot(cx);
 8599        let offset = self
 8600            .selections
 8601            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8602            .head();
 8603        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8604        let offset = excerpt.map_offset_to_buffer(offset);
 8605        let buffer_id = excerpt.buffer().remote_id();
 8606
 8607        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8608        let mut cursor = layer.node().walk();
 8609
 8610        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8611            if cursor.node().end_byte() == offset.0 {
 8612                cursor.goto_next_sibling();
 8613            }
 8614        }
 8615
 8616        // Ascend to the smallest ancestor that contains the range and has a task.
 8617        loop {
 8618            let node = cursor.node();
 8619            let node_range = node.byte_range();
 8620            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8621
 8622            // Check if this node contains our offset
 8623            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8624                // If it contains offset, check for task
 8625                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8626                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8627                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8628                }
 8629            }
 8630
 8631            if !cursor.goto_parent() {
 8632                break;
 8633            }
 8634        }
 8635        None
 8636    }
 8637
 8638    fn render_run_indicator(
 8639        &self,
 8640        _style: &EditorStyle,
 8641        is_active: bool,
 8642        row: DisplayRow,
 8643        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8644        cx: &mut Context<Self>,
 8645    ) -> IconButton {
 8646        let color = Color::Muted;
 8647        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8648
 8649        IconButton::new(
 8650            ("run_indicator", row.0 as usize),
 8651            ui::IconName::PlayOutlined,
 8652        )
 8653        .shape(ui::IconButtonShape::Square)
 8654        .icon_size(IconSize::XSmall)
 8655        .icon_color(color)
 8656        .toggle_state(is_active)
 8657        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8658            let quick_launch = match e {
 8659                ClickEvent::Keyboard(_) => true,
 8660                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8661            };
 8662
 8663            window.focus(&editor.focus_handle(cx));
 8664            editor.toggle_code_actions(
 8665                &ToggleCodeActions {
 8666                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8667                    quick_launch,
 8668                },
 8669                window,
 8670                cx,
 8671            );
 8672        }))
 8673        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8674            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8675        }))
 8676    }
 8677
 8678    pub fn context_menu_visible(&self) -> bool {
 8679        !self.edit_prediction_preview_is_active()
 8680            && self
 8681                .context_menu
 8682                .borrow()
 8683                .as_ref()
 8684                .is_some_and(|menu| menu.visible())
 8685    }
 8686
 8687    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8688        self.context_menu
 8689            .borrow()
 8690            .as_ref()
 8691            .map(|menu| menu.origin())
 8692    }
 8693
 8694    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8695        self.context_menu_options = Some(options);
 8696    }
 8697
 8698    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8699    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8700
 8701    fn render_edit_prediction_popover(
 8702        &mut self,
 8703        text_bounds: &Bounds<Pixels>,
 8704        content_origin: gpui::Point<Pixels>,
 8705        right_margin: Pixels,
 8706        editor_snapshot: &EditorSnapshot,
 8707        visible_row_range: Range<DisplayRow>,
 8708        scroll_top: ScrollOffset,
 8709        scroll_bottom: ScrollOffset,
 8710        line_layouts: &[LineWithInvisibles],
 8711        line_height: Pixels,
 8712        scroll_position: gpui::Point<ScrollOffset>,
 8713        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8714        newest_selection_head: Option<DisplayPoint>,
 8715        editor_width: Pixels,
 8716        style: &EditorStyle,
 8717        window: &mut Window,
 8718        cx: &mut App,
 8719    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8720        if self.mode().is_minimap() {
 8721            return None;
 8722        }
 8723        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8724
 8725        if self.edit_prediction_visible_in_cursor_popover(true) {
 8726            return None;
 8727        }
 8728
 8729        match &active_edit_prediction.completion {
 8730            EditPrediction::MoveWithin { target, .. } => {
 8731                let target_display_point = target.to_display_point(editor_snapshot);
 8732
 8733                if self.edit_prediction_requires_modifier() {
 8734                    if !self.edit_prediction_preview_is_active() {
 8735                        return None;
 8736                    }
 8737
 8738                    self.render_edit_prediction_modifier_jump_popover(
 8739                        text_bounds,
 8740                        content_origin,
 8741                        visible_row_range,
 8742                        line_layouts,
 8743                        line_height,
 8744                        scroll_pixel_position,
 8745                        newest_selection_head,
 8746                        target_display_point,
 8747                        window,
 8748                        cx,
 8749                    )
 8750                } else {
 8751                    self.render_edit_prediction_eager_jump_popover(
 8752                        text_bounds,
 8753                        content_origin,
 8754                        editor_snapshot,
 8755                        visible_row_range,
 8756                        scroll_top,
 8757                        scroll_bottom,
 8758                        line_height,
 8759                        scroll_pixel_position,
 8760                        target_display_point,
 8761                        editor_width,
 8762                        window,
 8763                        cx,
 8764                    )
 8765                }
 8766            }
 8767            EditPrediction::Edit {
 8768                display_mode: EditDisplayMode::Inline,
 8769                ..
 8770            } => None,
 8771            EditPrediction::Edit {
 8772                display_mode: EditDisplayMode::TabAccept,
 8773                edits,
 8774                ..
 8775            } => {
 8776                let range = &edits.first()?.0;
 8777                let target_display_point = range.end.to_display_point(editor_snapshot);
 8778
 8779                self.render_edit_prediction_end_of_line_popover(
 8780                    "Accept",
 8781                    editor_snapshot,
 8782                    visible_row_range,
 8783                    target_display_point,
 8784                    line_height,
 8785                    scroll_pixel_position,
 8786                    content_origin,
 8787                    editor_width,
 8788                    window,
 8789                    cx,
 8790                )
 8791            }
 8792            EditPrediction::Edit {
 8793                edits,
 8794                edit_preview,
 8795                display_mode: EditDisplayMode::DiffPopover,
 8796                snapshot,
 8797            } => self.render_edit_prediction_diff_popover(
 8798                text_bounds,
 8799                content_origin,
 8800                right_margin,
 8801                editor_snapshot,
 8802                visible_row_range,
 8803                line_layouts,
 8804                line_height,
 8805                scroll_position,
 8806                scroll_pixel_position,
 8807                newest_selection_head,
 8808                editor_width,
 8809                style,
 8810                edits,
 8811                edit_preview,
 8812                snapshot,
 8813                window,
 8814                cx,
 8815            ),
 8816            EditPrediction::MoveOutside { snapshot, .. } => {
 8817                let file_name = snapshot
 8818                    .file()
 8819                    .map(|file| file.file_name(cx))
 8820                    .unwrap_or("untitled");
 8821                let mut element = self
 8822                    .render_edit_prediction_line_popover(
 8823                        format!("Jump to {file_name}"),
 8824                        Some(IconName::ZedPredict),
 8825                        window,
 8826                        cx,
 8827                    )
 8828                    .into_any();
 8829
 8830                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8831                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8832                let origin_y = text_bounds.size.height - size.height - px(30.);
 8833                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8834                element.prepaint_at(origin, window, cx);
 8835
 8836                Some((element, origin))
 8837            }
 8838        }
 8839    }
 8840
 8841    fn render_edit_prediction_modifier_jump_popover(
 8842        &mut self,
 8843        text_bounds: &Bounds<Pixels>,
 8844        content_origin: gpui::Point<Pixels>,
 8845        visible_row_range: Range<DisplayRow>,
 8846        line_layouts: &[LineWithInvisibles],
 8847        line_height: Pixels,
 8848        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8849        newest_selection_head: Option<DisplayPoint>,
 8850        target_display_point: DisplayPoint,
 8851        window: &mut Window,
 8852        cx: &mut App,
 8853    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8854        let scrolled_content_origin =
 8855            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8856
 8857        const SCROLL_PADDING_Y: Pixels = px(12.);
 8858
 8859        if target_display_point.row() < visible_row_range.start {
 8860            return self.render_edit_prediction_scroll_popover(
 8861                |_| SCROLL_PADDING_Y,
 8862                IconName::ArrowUp,
 8863                visible_row_range,
 8864                line_layouts,
 8865                newest_selection_head,
 8866                scrolled_content_origin,
 8867                window,
 8868                cx,
 8869            );
 8870        } else if target_display_point.row() >= visible_row_range.end {
 8871            return self.render_edit_prediction_scroll_popover(
 8872                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8873                IconName::ArrowDown,
 8874                visible_row_range,
 8875                line_layouts,
 8876                newest_selection_head,
 8877                scrolled_content_origin,
 8878                window,
 8879                cx,
 8880            );
 8881        }
 8882
 8883        const POLE_WIDTH: Pixels = px(2.);
 8884
 8885        let line_layout =
 8886            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8887        let target_column = target_display_point.column() as usize;
 8888
 8889        let target_x = line_layout.x_for_index(target_column);
 8890        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8891            - scroll_pixel_position.y;
 8892
 8893        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8894
 8895        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8896        border_color.l += 0.001;
 8897
 8898        let mut element = v_flex()
 8899            .items_end()
 8900            .when(flag_on_right, |el| el.items_start())
 8901            .child(if flag_on_right {
 8902                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8903                    .rounded_bl(px(0.))
 8904                    .rounded_tl(px(0.))
 8905                    .border_l_2()
 8906                    .border_color(border_color)
 8907            } else {
 8908                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8909                    .rounded_br(px(0.))
 8910                    .rounded_tr(px(0.))
 8911                    .border_r_2()
 8912                    .border_color(border_color)
 8913            })
 8914            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8915            .into_any();
 8916
 8917        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8918
 8919        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8920            - point(
 8921                if flag_on_right {
 8922                    POLE_WIDTH
 8923                } else {
 8924                    size.width - POLE_WIDTH
 8925                },
 8926                size.height - line_height,
 8927            );
 8928
 8929        origin.x = origin.x.max(content_origin.x);
 8930
 8931        element.prepaint_at(origin, window, cx);
 8932
 8933        Some((element, origin))
 8934    }
 8935
 8936    fn render_edit_prediction_scroll_popover(
 8937        &mut self,
 8938        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8939        scroll_icon: IconName,
 8940        visible_row_range: Range<DisplayRow>,
 8941        line_layouts: &[LineWithInvisibles],
 8942        newest_selection_head: Option<DisplayPoint>,
 8943        scrolled_content_origin: gpui::Point<Pixels>,
 8944        window: &mut Window,
 8945        cx: &mut App,
 8946    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8947        let mut element = self
 8948            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8949            .into_any();
 8950
 8951        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8952
 8953        let cursor = newest_selection_head?;
 8954        let cursor_row_layout =
 8955            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8956        let cursor_column = cursor.column() as usize;
 8957
 8958        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8959
 8960        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8961
 8962        element.prepaint_at(origin, window, cx);
 8963        Some((element, origin))
 8964    }
 8965
 8966    fn render_edit_prediction_eager_jump_popover(
 8967        &mut self,
 8968        text_bounds: &Bounds<Pixels>,
 8969        content_origin: gpui::Point<Pixels>,
 8970        editor_snapshot: &EditorSnapshot,
 8971        visible_row_range: Range<DisplayRow>,
 8972        scroll_top: ScrollOffset,
 8973        scroll_bottom: ScrollOffset,
 8974        line_height: Pixels,
 8975        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8976        target_display_point: DisplayPoint,
 8977        editor_width: Pixels,
 8978        window: &mut Window,
 8979        cx: &mut App,
 8980    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8981        if target_display_point.row().as_f64() < scroll_top {
 8982            let mut element = self
 8983                .render_edit_prediction_line_popover(
 8984                    "Jump to Edit",
 8985                    Some(IconName::ArrowUp),
 8986                    window,
 8987                    cx,
 8988                )
 8989                .into_any();
 8990
 8991            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8992            let offset = point(
 8993                (text_bounds.size.width - size.width) / 2.,
 8994                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8995            );
 8996
 8997            let origin = text_bounds.origin + offset;
 8998            element.prepaint_at(origin, window, cx);
 8999            Some((element, origin))
 9000        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9001            let mut element = self
 9002                .render_edit_prediction_line_popover(
 9003                    "Jump to Edit",
 9004                    Some(IconName::ArrowDown),
 9005                    window,
 9006                    cx,
 9007                )
 9008                .into_any();
 9009
 9010            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9011            let offset = point(
 9012                (text_bounds.size.width - size.width) / 2.,
 9013                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9014            );
 9015
 9016            let origin = text_bounds.origin + offset;
 9017            element.prepaint_at(origin, window, cx);
 9018            Some((element, origin))
 9019        } else {
 9020            self.render_edit_prediction_end_of_line_popover(
 9021                "Jump to Edit",
 9022                editor_snapshot,
 9023                visible_row_range,
 9024                target_display_point,
 9025                line_height,
 9026                scroll_pixel_position,
 9027                content_origin,
 9028                editor_width,
 9029                window,
 9030                cx,
 9031            )
 9032        }
 9033    }
 9034
 9035    fn render_edit_prediction_end_of_line_popover(
 9036        self: &mut Editor,
 9037        label: &'static str,
 9038        editor_snapshot: &EditorSnapshot,
 9039        visible_row_range: Range<DisplayRow>,
 9040        target_display_point: DisplayPoint,
 9041        line_height: Pixels,
 9042        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9043        content_origin: gpui::Point<Pixels>,
 9044        editor_width: Pixels,
 9045        window: &mut Window,
 9046        cx: &mut App,
 9047    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9048        let target_line_end = DisplayPoint::new(
 9049            target_display_point.row(),
 9050            editor_snapshot.line_len(target_display_point.row()),
 9051        );
 9052
 9053        let mut element = self
 9054            .render_edit_prediction_line_popover(label, None, window, cx)
 9055            .into_any();
 9056
 9057        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9058
 9059        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9060
 9061        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9062        let mut origin = start_point
 9063            + line_origin
 9064            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9065        origin.x = origin.x.max(content_origin.x);
 9066
 9067        let max_x = content_origin.x + editor_width - size.width;
 9068
 9069        if origin.x > max_x {
 9070            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9071
 9072            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9073                origin.y += offset;
 9074                IconName::ArrowUp
 9075            } else {
 9076                origin.y -= offset;
 9077                IconName::ArrowDown
 9078            };
 9079
 9080            element = self
 9081                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9082                .into_any();
 9083
 9084            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9085
 9086            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9087        }
 9088
 9089        element.prepaint_at(origin, window, cx);
 9090        Some((element, origin))
 9091    }
 9092
 9093    fn render_edit_prediction_diff_popover(
 9094        self: &Editor,
 9095        text_bounds: &Bounds<Pixels>,
 9096        content_origin: gpui::Point<Pixels>,
 9097        right_margin: Pixels,
 9098        editor_snapshot: &EditorSnapshot,
 9099        visible_row_range: Range<DisplayRow>,
 9100        line_layouts: &[LineWithInvisibles],
 9101        line_height: Pixels,
 9102        scroll_position: gpui::Point<ScrollOffset>,
 9103        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9104        newest_selection_head: Option<DisplayPoint>,
 9105        editor_width: Pixels,
 9106        style: &EditorStyle,
 9107        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9108        edit_preview: &Option<language::EditPreview>,
 9109        snapshot: &language::BufferSnapshot,
 9110        window: &mut Window,
 9111        cx: &mut App,
 9112    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9113        let edit_start = edits
 9114            .first()
 9115            .unwrap()
 9116            .0
 9117            .start
 9118            .to_display_point(editor_snapshot);
 9119        let edit_end = edits
 9120            .last()
 9121            .unwrap()
 9122            .0
 9123            .end
 9124            .to_display_point(editor_snapshot);
 9125
 9126        let is_visible = visible_row_range.contains(&edit_start.row())
 9127            || visible_row_range.contains(&edit_end.row());
 9128        if !is_visible {
 9129            return None;
 9130        }
 9131
 9132        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9133            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9134        } else {
 9135            // Fallback for providers without edit_preview
 9136            crate::edit_prediction_fallback_text(edits, cx)
 9137        };
 9138
 9139        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9140        let line_count = highlighted_edits.text.lines().count();
 9141
 9142        const BORDER_WIDTH: Pixels = px(1.);
 9143
 9144        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9145        let has_keybind = keybind.is_some();
 9146
 9147        let mut element = h_flex()
 9148            .items_start()
 9149            .child(
 9150                h_flex()
 9151                    .bg(cx.theme().colors().editor_background)
 9152                    .border(BORDER_WIDTH)
 9153                    .shadow_xs()
 9154                    .border_color(cx.theme().colors().border)
 9155                    .rounded_l_lg()
 9156                    .when(line_count > 1, |el| el.rounded_br_lg())
 9157                    .pr_1()
 9158                    .child(styled_text),
 9159            )
 9160            .child(
 9161                h_flex()
 9162                    .h(line_height + BORDER_WIDTH * 2.)
 9163                    .px_1p5()
 9164                    .gap_1()
 9165                    // Workaround: For some reason, there's a gap if we don't do this
 9166                    .ml(-BORDER_WIDTH)
 9167                    .shadow(vec![gpui::BoxShadow {
 9168                        color: gpui::black().opacity(0.05),
 9169                        offset: point(px(1.), px(1.)),
 9170                        blur_radius: px(2.),
 9171                        spread_radius: px(0.),
 9172                    }])
 9173                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9174                    .border(BORDER_WIDTH)
 9175                    .border_color(cx.theme().colors().border)
 9176                    .rounded_r_lg()
 9177                    .id("edit_prediction_diff_popover_keybind")
 9178                    .when(!has_keybind, |el| {
 9179                        let status_colors = cx.theme().status();
 9180
 9181                        el.bg(status_colors.error_background)
 9182                            .border_color(status_colors.error.opacity(0.6))
 9183                            .child(Icon::new(IconName::Info).color(Color::Error))
 9184                            .cursor_default()
 9185                            .hoverable_tooltip(move |_window, cx| {
 9186                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9187                            })
 9188                    })
 9189                    .children(keybind),
 9190            )
 9191            .into_any();
 9192
 9193        let longest_row =
 9194            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9195        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9196            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9197        } else {
 9198            layout_line(
 9199                longest_row,
 9200                editor_snapshot,
 9201                style,
 9202                editor_width,
 9203                |_| false,
 9204                window,
 9205                cx,
 9206            )
 9207            .width
 9208        };
 9209
 9210        let viewport_bounds =
 9211            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9212                right: -right_margin,
 9213                ..Default::default()
 9214            });
 9215
 9216        let x_after_longest = Pixels::from(
 9217            ScrollPixelOffset::from(
 9218                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9219            ) - scroll_pixel_position.x,
 9220        );
 9221
 9222        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9223
 9224        // Fully visible if it can be displayed within the window (allow overlapping other
 9225        // panes). However, this is only allowed if the popover starts within text_bounds.
 9226        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9227            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9228
 9229        let mut origin = if can_position_to_the_right {
 9230            point(
 9231                x_after_longest,
 9232                text_bounds.origin.y
 9233                    + Pixels::from(
 9234                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9235                            - scroll_pixel_position.y,
 9236                    ),
 9237            )
 9238        } else {
 9239            let cursor_row = newest_selection_head.map(|head| head.row());
 9240            let above_edit = edit_start
 9241                .row()
 9242                .0
 9243                .checked_sub(line_count as u32)
 9244                .map(DisplayRow);
 9245            let below_edit = Some(edit_end.row() + 1);
 9246            let above_cursor =
 9247                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9248            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9249
 9250            // Place the edit popover adjacent to the edit if there is a location
 9251            // available that is onscreen and does not obscure the cursor. Otherwise,
 9252            // place it adjacent to the cursor.
 9253            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9254                .into_iter()
 9255                .flatten()
 9256                .find(|&start_row| {
 9257                    let end_row = start_row + line_count as u32;
 9258                    visible_row_range.contains(&start_row)
 9259                        && visible_row_range.contains(&end_row)
 9260                        && cursor_row
 9261                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9262                })?;
 9263
 9264            content_origin
 9265                + point(
 9266                    Pixels::from(-scroll_pixel_position.x),
 9267                    Pixels::from(
 9268                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9269                    ),
 9270                )
 9271        };
 9272
 9273        origin.x -= BORDER_WIDTH;
 9274
 9275        window.defer_draw(element, origin, 1);
 9276
 9277        // Do not return an element, since it will already be drawn due to defer_draw.
 9278        None
 9279    }
 9280
 9281    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9282        px(30.)
 9283    }
 9284
 9285    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9286        if self.read_only(cx) {
 9287            cx.theme().players().read_only()
 9288        } else {
 9289            self.style.as_ref().unwrap().local_player
 9290        }
 9291    }
 9292
 9293    fn render_edit_prediction_accept_keybind(
 9294        &self,
 9295        window: &mut Window,
 9296        cx: &mut App,
 9297    ) -> Option<AnyElement> {
 9298        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9299        let accept_keystroke = accept_binding.keystroke()?;
 9300
 9301        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9302
 9303        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9304            Color::Accent
 9305        } else {
 9306            Color::Muted
 9307        };
 9308
 9309        h_flex()
 9310            .px_0p5()
 9311            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9312            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9313            .text_size(TextSize::XSmall.rems(cx))
 9314            .child(h_flex().children(ui::render_modifiers(
 9315                accept_keystroke.modifiers(),
 9316                PlatformStyle::platform(),
 9317                Some(modifiers_color),
 9318                Some(IconSize::XSmall.rems().into()),
 9319                true,
 9320            )))
 9321            .when(is_platform_style_mac, |parent| {
 9322                parent.child(accept_keystroke.key().to_string())
 9323            })
 9324            .when(!is_platform_style_mac, |parent| {
 9325                parent.child(
 9326                    Key::new(
 9327                        util::capitalize(accept_keystroke.key()),
 9328                        Some(Color::Default),
 9329                    )
 9330                    .size(Some(IconSize::XSmall.rems().into())),
 9331                )
 9332            })
 9333            .into_any()
 9334            .into()
 9335    }
 9336
 9337    fn render_edit_prediction_line_popover(
 9338        &self,
 9339        label: impl Into<SharedString>,
 9340        icon: Option<IconName>,
 9341        window: &mut Window,
 9342        cx: &mut App,
 9343    ) -> Stateful<Div> {
 9344        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9345
 9346        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9347        let has_keybind = keybind.is_some();
 9348
 9349        h_flex()
 9350            .id("ep-line-popover")
 9351            .py_0p5()
 9352            .pl_1()
 9353            .pr(padding_right)
 9354            .gap_1()
 9355            .rounded_md()
 9356            .border_1()
 9357            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9358            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9359            .shadow_xs()
 9360            .when(!has_keybind, |el| {
 9361                let status_colors = cx.theme().status();
 9362
 9363                el.bg(status_colors.error_background)
 9364                    .border_color(status_colors.error.opacity(0.6))
 9365                    .pl_2()
 9366                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9367                    .cursor_default()
 9368                    .hoverable_tooltip(move |_window, cx| {
 9369                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9370                    })
 9371            })
 9372            .children(keybind)
 9373            .child(
 9374                Label::new(label)
 9375                    .size(LabelSize::Small)
 9376                    .when(!has_keybind, |el| {
 9377                        el.color(cx.theme().status().error.into()).strikethrough()
 9378                    }),
 9379            )
 9380            .when(!has_keybind, |el| {
 9381                el.child(
 9382                    h_flex().ml_1().child(
 9383                        Icon::new(IconName::Info)
 9384                            .size(IconSize::Small)
 9385                            .color(cx.theme().status().error.into()),
 9386                    ),
 9387                )
 9388            })
 9389            .when_some(icon, |element, icon| {
 9390                element.child(
 9391                    div()
 9392                        .mt(px(1.5))
 9393                        .child(Icon::new(icon).size(IconSize::Small)),
 9394                )
 9395            })
 9396    }
 9397
 9398    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9399        let accent_color = cx.theme().colors().text_accent;
 9400        let editor_bg_color = cx.theme().colors().editor_background;
 9401        editor_bg_color.blend(accent_color.opacity(0.1))
 9402    }
 9403
 9404    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9405        let accent_color = cx.theme().colors().text_accent;
 9406        let editor_bg_color = cx.theme().colors().editor_background;
 9407        editor_bg_color.blend(accent_color.opacity(0.6))
 9408    }
 9409    fn get_prediction_provider_icon_name(
 9410        provider: &Option<RegisteredEditPredictionProvider>,
 9411    ) -> IconName {
 9412        match provider {
 9413            Some(provider) => match provider.provider.name() {
 9414                "copilot" => IconName::Copilot,
 9415                "supermaven" => IconName::Supermaven,
 9416                _ => IconName::ZedPredict,
 9417            },
 9418            None => IconName::ZedPredict,
 9419        }
 9420    }
 9421
 9422    fn render_edit_prediction_cursor_popover(
 9423        &self,
 9424        min_width: Pixels,
 9425        max_width: Pixels,
 9426        cursor_point: Point,
 9427        style: &EditorStyle,
 9428        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9429        _window: &Window,
 9430        cx: &mut Context<Editor>,
 9431    ) -> Option<AnyElement> {
 9432        let provider = self.edit_prediction_provider.as_ref()?;
 9433        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9434
 9435        let is_refreshing = provider.provider.is_refreshing(cx);
 9436
 9437        fn pending_completion_container(icon: IconName) -> Div {
 9438            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9439        }
 9440
 9441        let completion = match &self.active_edit_prediction {
 9442            Some(prediction) => {
 9443                if !self.has_visible_completions_menu() {
 9444                    const RADIUS: Pixels = px(6.);
 9445                    const BORDER_WIDTH: Pixels = px(1.);
 9446
 9447                    return Some(
 9448                        h_flex()
 9449                            .elevation_2(cx)
 9450                            .border(BORDER_WIDTH)
 9451                            .border_color(cx.theme().colors().border)
 9452                            .when(accept_keystroke.is_none(), |el| {
 9453                                el.border_color(cx.theme().status().error)
 9454                            })
 9455                            .rounded(RADIUS)
 9456                            .rounded_tl(px(0.))
 9457                            .overflow_hidden()
 9458                            .child(div().px_1p5().child(match &prediction.completion {
 9459                                EditPrediction::MoveWithin { target, snapshot } => {
 9460                                    use text::ToPoint as _;
 9461                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9462                                    {
 9463                                        Icon::new(IconName::ZedPredictDown)
 9464                                    } else {
 9465                                        Icon::new(IconName::ZedPredictUp)
 9466                                    }
 9467                                }
 9468                                EditPrediction::MoveOutside { .. } => {
 9469                                    // TODO [zeta2] custom icon for external jump?
 9470                                    Icon::new(provider_icon)
 9471                                }
 9472                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9473                            }))
 9474                            .child(
 9475                                h_flex()
 9476                                    .gap_1()
 9477                                    .py_1()
 9478                                    .px_2()
 9479                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9480                                    .border_l_1()
 9481                                    .border_color(cx.theme().colors().border)
 9482                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9483                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9484                                        el.child(
 9485                                            Label::new("Hold")
 9486                                                .size(LabelSize::Small)
 9487                                                .when(accept_keystroke.is_none(), |el| {
 9488                                                    el.strikethrough()
 9489                                                })
 9490                                                .line_height_style(LineHeightStyle::UiLabel),
 9491                                        )
 9492                                    })
 9493                                    .id("edit_prediction_cursor_popover_keybind")
 9494                                    .when(accept_keystroke.is_none(), |el| {
 9495                                        let status_colors = cx.theme().status();
 9496
 9497                                        el.bg(status_colors.error_background)
 9498                                            .border_color(status_colors.error.opacity(0.6))
 9499                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9500                                            .cursor_default()
 9501                                            .hoverable_tooltip(move |_window, cx| {
 9502                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9503                                                    .into()
 9504                                            })
 9505                                    })
 9506                                    .when_some(
 9507                                        accept_keystroke.as_ref(),
 9508                                        |el, accept_keystroke| {
 9509                                            el.child(h_flex().children(ui::render_modifiers(
 9510                                                accept_keystroke.modifiers(),
 9511                                                PlatformStyle::platform(),
 9512                                                Some(Color::Default),
 9513                                                Some(IconSize::XSmall.rems().into()),
 9514                                                false,
 9515                                            )))
 9516                                        },
 9517                                    ),
 9518                            )
 9519                            .into_any(),
 9520                    );
 9521                }
 9522
 9523                self.render_edit_prediction_cursor_popover_preview(
 9524                    prediction,
 9525                    cursor_point,
 9526                    style,
 9527                    cx,
 9528                )?
 9529            }
 9530
 9531            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9532                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9533                    stale_completion,
 9534                    cursor_point,
 9535                    style,
 9536                    cx,
 9537                )?,
 9538
 9539                None => pending_completion_container(provider_icon)
 9540                    .child(Label::new("...").size(LabelSize::Small)),
 9541            },
 9542
 9543            None => pending_completion_container(provider_icon)
 9544                .child(Label::new("...").size(LabelSize::Small)),
 9545        };
 9546
 9547        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9548            completion
 9549                .with_animation(
 9550                    "loading-completion",
 9551                    Animation::new(Duration::from_secs(2))
 9552                        .repeat()
 9553                        .with_easing(pulsating_between(0.4, 0.8)),
 9554                    |label, delta| label.opacity(delta),
 9555                )
 9556                .into_any_element()
 9557        } else {
 9558            completion.into_any_element()
 9559        };
 9560
 9561        let has_completion = self.active_edit_prediction.is_some();
 9562
 9563        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9564        Some(
 9565            h_flex()
 9566                .min_w(min_width)
 9567                .max_w(max_width)
 9568                .flex_1()
 9569                .elevation_2(cx)
 9570                .border_color(cx.theme().colors().border)
 9571                .child(
 9572                    div()
 9573                        .flex_1()
 9574                        .py_1()
 9575                        .px_2()
 9576                        .overflow_hidden()
 9577                        .child(completion),
 9578                )
 9579                .when_some(accept_keystroke, |el, accept_keystroke| {
 9580                    if !accept_keystroke.modifiers().modified() {
 9581                        return el;
 9582                    }
 9583
 9584                    el.child(
 9585                        h_flex()
 9586                            .h_full()
 9587                            .border_l_1()
 9588                            .rounded_r_lg()
 9589                            .border_color(cx.theme().colors().border)
 9590                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9591                            .gap_1()
 9592                            .py_1()
 9593                            .px_2()
 9594                            .child(
 9595                                h_flex()
 9596                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9597                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9598                                    .child(h_flex().children(ui::render_modifiers(
 9599                                        accept_keystroke.modifiers(),
 9600                                        PlatformStyle::platform(),
 9601                                        Some(if !has_completion {
 9602                                            Color::Muted
 9603                                        } else {
 9604                                            Color::Default
 9605                                        }),
 9606                                        None,
 9607                                        false,
 9608                                    ))),
 9609                            )
 9610                            .child(Label::new("Preview").into_any_element())
 9611                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9612                    )
 9613                })
 9614                .into_any(),
 9615        )
 9616    }
 9617
 9618    fn render_edit_prediction_cursor_popover_preview(
 9619        &self,
 9620        completion: &EditPredictionState,
 9621        cursor_point: Point,
 9622        style: &EditorStyle,
 9623        cx: &mut Context<Editor>,
 9624    ) -> Option<Div> {
 9625        use text::ToPoint as _;
 9626
 9627        fn render_relative_row_jump(
 9628            prefix: impl Into<String>,
 9629            current_row: u32,
 9630            target_row: u32,
 9631        ) -> Div {
 9632            let (row_diff, arrow) = if target_row < current_row {
 9633                (current_row - target_row, IconName::ArrowUp)
 9634            } else {
 9635                (target_row - current_row, IconName::ArrowDown)
 9636            };
 9637
 9638            h_flex()
 9639                .child(
 9640                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9641                        .color(Color::Muted)
 9642                        .size(LabelSize::Small),
 9643                )
 9644                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9645        }
 9646
 9647        let supports_jump = self
 9648            .edit_prediction_provider
 9649            .as_ref()
 9650            .map(|provider| provider.provider.supports_jump_to_edit())
 9651            .unwrap_or(true);
 9652
 9653        match &completion.completion {
 9654            EditPrediction::MoveWithin {
 9655                target, snapshot, ..
 9656            } => {
 9657                if !supports_jump {
 9658                    return None;
 9659                }
 9660
 9661                Some(
 9662                    h_flex()
 9663                        .px_2()
 9664                        .gap_2()
 9665                        .flex_1()
 9666                        .child(
 9667                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9668                                Icon::new(IconName::ZedPredictDown)
 9669                            } else {
 9670                                Icon::new(IconName::ZedPredictUp)
 9671                            },
 9672                        )
 9673                        .child(Label::new("Jump to Edit")),
 9674                )
 9675            }
 9676            EditPrediction::MoveOutside { snapshot, .. } => {
 9677                let file_name = snapshot
 9678                    .file()
 9679                    .map(|file| file.file_name(cx))
 9680                    .unwrap_or("untitled");
 9681                Some(
 9682                    h_flex()
 9683                        .px_2()
 9684                        .gap_2()
 9685                        .flex_1()
 9686                        .child(Icon::new(IconName::ZedPredict))
 9687                        .child(Label::new(format!("Jump to {file_name}"))),
 9688                )
 9689            }
 9690            EditPrediction::Edit {
 9691                edits,
 9692                edit_preview,
 9693                snapshot,
 9694                display_mode: _,
 9695            } => {
 9696                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9697
 9698                let (highlighted_edits, has_more_lines) =
 9699                    if let Some(edit_preview) = edit_preview.as_ref() {
 9700                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9701                            .first_line_preview()
 9702                    } else {
 9703                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9704                    };
 9705
 9706                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9707                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9708
 9709                let preview = h_flex()
 9710                    .gap_1()
 9711                    .min_w_16()
 9712                    .child(styled_text)
 9713                    .when(has_more_lines, |parent| parent.child(""));
 9714
 9715                let left = if supports_jump && first_edit_row != cursor_point.row {
 9716                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9717                        .into_any_element()
 9718                } else {
 9719                    let icon_name =
 9720                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9721                    Icon::new(icon_name).into_any_element()
 9722                };
 9723
 9724                Some(
 9725                    h_flex()
 9726                        .h_full()
 9727                        .flex_1()
 9728                        .gap_2()
 9729                        .pr_1()
 9730                        .overflow_x_hidden()
 9731                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9732                        .child(left)
 9733                        .child(preview),
 9734                )
 9735            }
 9736        }
 9737    }
 9738
 9739    pub fn render_context_menu(
 9740        &self,
 9741        style: &EditorStyle,
 9742        max_height_in_lines: u32,
 9743        window: &mut Window,
 9744        cx: &mut Context<Editor>,
 9745    ) -> Option<AnyElement> {
 9746        let menu = self.context_menu.borrow();
 9747        let menu = menu.as_ref()?;
 9748        if !menu.visible() {
 9749            return None;
 9750        };
 9751        Some(menu.render(style, max_height_in_lines, window, cx))
 9752    }
 9753
 9754    fn render_context_menu_aside(
 9755        &mut self,
 9756        max_size: Size<Pixels>,
 9757        window: &mut Window,
 9758        cx: &mut Context<Editor>,
 9759    ) -> Option<AnyElement> {
 9760        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9761            if menu.visible() {
 9762                menu.render_aside(max_size, window, cx)
 9763            } else {
 9764                None
 9765            }
 9766        })
 9767    }
 9768
 9769    fn hide_context_menu(
 9770        &mut self,
 9771        window: &mut Window,
 9772        cx: &mut Context<Self>,
 9773    ) -> Option<CodeContextMenu> {
 9774        cx.notify();
 9775        self.completion_tasks.clear();
 9776        let context_menu = self.context_menu.borrow_mut().take();
 9777        self.stale_edit_prediction_in_menu.take();
 9778        self.update_visible_edit_prediction(window, cx);
 9779        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9780            && let Some(completion_provider) = &self.completion_provider
 9781        {
 9782            completion_provider.selection_changed(None, window, cx);
 9783        }
 9784        context_menu
 9785    }
 9786
 9787    fn show_snippet_choices(
 9788        &mut self,
 9789        choices: &Vec<String>,
 9790        selection: Range<Anchor>,
 9791        cx: &mut Context<Self>,
 9792    ) {
 9793        let Some((_, buffer, _)) = self
 9794            .buffer()
 9795            .read(cx)
 9796            .excerpt_containing(selection.start, cx)
 9797        else {
 9798            return;
 9799        };
 9800        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9801        else {
 9802            return;
 9803        };
 9804        if buffer != end_buffer {
 9805            log::error!("expected anchor range to have matching buffer IDs");
 9806            return;
 9807        }
 9808
 9809        let id = post_inc(&mut self.next_completion_id);
 9810        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9811        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9812            CompletionsMenu::new_snippet_choices(
 9813                id,
 9814                true,
 9815                choices,
 9816                selection,
 9817                buffer,
 9818                snippet_sort_order,
 9819            ),
 9820        ));
 9821    }
 9822
 9823    pub fn insert_snippet(
 9824        &mut self,
 9825        insertion_ranges: &[Range<MultiBufferOffset>],
 9826        snippet: Snippet,
 9827        window: &mut Window,
 9828        cx: &mut Context<Self>,
 9829    ) -> Result<()> {
 9830        struct Tabstop<T> {
 9831            is_end_tabstop: bool,
 9832            ranges: Vec<Range<T>>,
 9833            choices: Option<Vec<String>>,
 9834        }
 9835
 9836        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9837            let snippet_text: Arc<str> = snippet.text.clone().into();
 9838            let edits = insertion_ranges
 9839                .iter()
 9840                .cloned()
 9841                .map(|range| (range, snippet_text.clone()));
 9842            let autoindent_mode = AutoindentMode::Block {
 9843                original_indent_columns: Vec::new(),
 9844            };
 9845            buffer.edit(edits, Some(autoindent_mode), cx);
 9846
 9847            let snapshot = &*buffer.read(cx);
 9848            let snippet = &snippet;
 9849            snippet
 9850                .tabstops
 9851                .iter()
 9852                .map(|tabstop| {
 9853                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9854                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9855                    });
 9856                    let mut tabstop_ranges = tabstop
 9857                        .ranges
 9858                        .iter()
 9859                        .flat_map(|tabstop_range| {
 9860                            let mut delta = 0_isize;
 9861                            insertion_ranges.iter().map(move |insertion_range| {
 9862                                let insertion_start = insertion_range.start + delta;
 9863                                delta += snippet.text.len() as isize
 9864                                    - (insertion_range.end - insertion_range.start) as isize;
 9865
 9866                                let start =
 9867                                    (insertion_start + tabstop_range.start).min(snapshot.len());
 9868                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
 9869                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9870                            })
 9871                        })
 9872                        .collect::<Vec<_>>();
 9873                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9874
 9875                    Tabstop {
 9876                        is_end_tabstop,
 9877                        ranges: tabstop_ranges,
 9878                        choices: tabstop.choices.clone(),
 9879                    }
 9880                })
 9881                .collect::<Vec<_>>()
 9882        });
 9883        if let Some(tabstop) = tabstops.first() {
 9884            self.change_selections(Default::default(), window, cx, |s| {
 9885                // Reverse order so that the first range is the newest created selection.
 9886                // Completions will use it and autoscroll will prioritize it.
 9887                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9888            });
 9889
 9890            if let Some(choices) = &tabstop.choices
 9891                && let Some(selection) = tabstop.ranges.first()
 9892            {
 9893                self.show_snippet_choices(choices, selection.clone(), cx)
 9894            }
 9895
 9896            // If we're already at the last tabstop and it's at the end of the snippet,
 9897            // we're done, we don't need to keep the state around.
 9898            if !tabstop.is_end_tabstop {
 9899                let choices = tabstops
 9900                    .iter()
 9901                    .map(|tabstop| tabstop.choices.clone())
 9902                    .collect();
 9903
 9904                let ranges = tabstops
 9905                    .into_iter()
 9906                    .map(|tabstop| tabstop.ranges)
 9907                    .collect::<Vec<_>>();
 9908
 9909                self.snippet_stack.push(SnippetState {
 9910                    active_index: 0,
 9911                    ranges,
 9912                    choices,
 9913                });
 9914            }
 9915
 9916            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9917            if self.autoclose_regions.is_empty() {
 9918                let snapshot = self.buffer.read(cx).snapshot(cx);
 9919                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9920                    let selection_head = selection.head();
 9921                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9922                        continue;
 9923                    };
 9924
 9925                    let mut bracket_pair = None;
 9926                    let max_lookup_length = scope
 9927                        .brackets()
 9928                        .map(|(pair, _)| {
 9929                            pair.start
 9930                                .as_str()
 9931                                .chars()
 9932                                .count()
 9933                                .max(pair.end.as_str().chars().count())
 9934                        })
 9935                        .max();
 9936                    if let Some(max_lookup_length) = max_lookup_length {
 9937                        let next_text = snapshot
 9938                            .chars_at(selection_head)
 9939                            .take(max_lookup_length)
 9940                            .collect::<String>();
 9941                        let prev_text = snapshot
 9942                            .reversed_chars_at(selection_head)
 9943                            .take(max_lookup_length)
 9944                            .collect::<String>();
 9945
 9946                        for (pair, enabled) in scope.brackets() {
 9947                            if enabled
 9948                                && pair.close
 9949                                && prev_text.starts_with(pair.start.as_str())
 9950                                && next_text.starts_with(pair.end.as_str())
 9951                            {
 9952                                bracket_pair = Some(pair.clone());
 9953                                break;
 9954                            }
 9955                        }
 9956                    }
 9957
 9958                    if let Some(pair) = bracket_pair {
 9959                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9960                        let autoclose_enabled =
 9961                            self.use_autoclose && snapshot_settings.use_autoclose;
 9962                        if autoclose_enabled {
 9963                            let start = snapshot.anchor_after(selection_head);
 9964                            let end = snapshot.anchor_after(selection_head);
 9965                            self.autoclose_regions.push(AutocloseRegion {
 9966                                selection_id: selection.id,
 9967                                range: start..end,
 9968                                pair,
 9969                            });
 9970                        }
 9971                    }
 9972                }
 9973            }
 9974        }
 9975        Ok(())
 9976    }
 9977
 9978    pub fn move_to_next_snippet_tabstop(
 9979        &mut self,
 9980        window: &mut Window,
 9981        cx: &mut Context<Self>,
 9982    ) -> bool {
 9983        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9984    }
 9985
 9986    pub fn move_to_prev_snippet_tabstop(
 9987        &mut self,
 9988        window: &mut Window,
 9989        cx: &mut Context<Self>,
 9990    ) -> bool {
 9991        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9992    }
 9993
 9994    pub fn move_to_snippet_tabstop(
 9995        &mut self,
 9996        bias: Bias,
 9997        window: &mut Window,
 9998        cx: &mut Context<Self>,
 9999    ) -> bool {
10000        if let Some(mut snippet) = self.snippet_stack.pop() {
10001            match bias {
10002                Bias::Left => {
10003                    if snippet.active_index > 0 {
10004                        snippet.active_index -= 1;
10005                    } else {
10006                        self.snippet_stack.push(snippet);
10007                        return false;
10008                    }
10009                }
10010                Bias::Right => {
10011                    if snippet.active_index + 1 < snippet.ranges.len() {
10012                        snippet.active_index += 1;
10013                    } else {
10014                        self.snippet_stack.push(snippet);
10015                        return false;
10016                    }
10017                }
10018            }
10019            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10020                self.change_selections(Default::default(), window, cx, |s| {
10021                    // Reverse order so that the first range is the newest created selection.
10022                    // Completions will use it and autoscroll will prioritize it.
10023                    s.select_ranges(current_ranges.iter().rev().cloned())
10024                });
10025
10026                if let Some(choices) = &snippet.choices[snippet.active_index]
10027                    && let Some(selection) = current_ranges.first()
10028                {
10029                    self.show_snippet_choices(choices, selection.clone(), cx);
10030                }
10031
10032                // If snippet state is not at the last tabstop, push it back on the stack
10033                if snippet.active_index + 1 < snippet.ranges.len() {
10034                    self.snippet_stack.push(snippet);
10035                }
10036                return true;
10037            }
10038        }
10039
10040        false
10041    }
10042
10043    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10044        self.transact(window, cx, |this, window, cx| {
10045            this.select_all(&SelectAll, window, cx);
10046            this.insert("", window, cx);
10047        });
10048    }
10049
10050    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10051        if self.read_only(cx) {
10052            return;
10053        }
10054        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10055        self.transact(window, cx, |this, window, cx| {
10056            this.select_autoclose_pair(window, cx);
10057
10058            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10059
10060            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10061            if !this.linked_edit_ranges.is_empty() {
10062                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10063                let snapshot = this.buffer.read(cx).snapshot(cx);
10064
10065                for selection in selections.iter() {
10066                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10067                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10068                    if selection_start.buffer_id != selection_end.buffer_id {
10069                        continue;
10070                    }
10071                    if let Some(ranges) =
10072                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10073                    {
10074                        for (buffer, entries) in ranges {
10075                            linked_ranges.entry(buffer).or_default().extend(entries);
10076                        }
10077                    }
10078                }
10079            }
10080
10081            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10082            for selection in &mut selections {
10083                if selection.is_empty() {
10084                    let old_head = selection.head();
10085                    let mut new_head =
10086                        movement::left(&display_map, old_head.to_display_point(&display_map))
10087                            .to_point(&display_map);
10088                    if let Some((buffer, line_buffer_range)) = display_map
10089                        .buffer_snapshot()
10090                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10091                    {
10092                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10093                        let indent_len = match indent_size.kind {
10094                            IndentKind::Space => {
10095                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10096                            }
10097                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10098                        };
10099                        if old_head.column <= indent_size.len && old_head.column > 0 {
10100                            let indent_len = indent_len.get();
10101                            new_head = cmp::min(
10102                                new_head,
10103                                MultiBufferPoint::new(
10104                                    old_head.row,
10105                                    ((old_head.column - 1) / indent_len) * indent_len,
10106                                ),
10107                            );
10108                        }
10109                    }
10110
10111                    selection.set_head(new_head, SelectionGoal::None);
10112                }
10113            }
10114
10115            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10116            this.insert("", window, cx);
10117            let empty_str: Arc<str> = Arc::from("");
10118            for (buffer, edits) in linked_ranges {
10119                let snapshot = buffer.read(cx).snapshot();
10120                use text::ToPoint as TP;
10121
10122                let edits = edits
10123                    .into_iter()
10124                    .map(|range| {
10125                        let end_point = TP::to_point(&range.end, &snapshot);
10126                        let mut start_point = TP::to_point(&range.start, &snapshot);
10127
10128                        if end_point == start_point {
10129                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10130                                .saturating_sub(1);
10131                            start_point =
10132                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10133                        };
10134
10135                        (start_point..end_point, empty_str.clone())
10136                    })
10137                    .sorted_by_key(|(range, _)| range.start)
10138                    .collect::<Vec<_>>();
10139                buffer.update(cx, |this, cx| {
10140                    this.edit(edits, None, cx);
10141                })
10142            }
10143            this.refresh_edit_prediction(true, false, window, cx);
10144            refresh_linked_ranges(this, window, cx);
10145        });
10146    }
10147
10148    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10149        if self.read_only(cx) {
10150            return;
10151        }
10152        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10153        self.transact(window, cx, |this, window, cx| {
10154            this.change_selections(Default::default(), window, cx, |s| {
10155                s.move_with(|map, selection| {
10156                    if selection.is_empty() {
10157                        let cursor = movement::right(map, selection.head());
10158                        selection.end = cursor;
10159                        selection.reversed = true;
10160                        selection.goal = SelectionGoal::None;
10161                    }
10162                })
10163            });
10164            this.insert("", window, cx);
10165            this.refresh_edit_prediction(true, false, window, cx);
10166        });
10167    }
10168
10169    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10170        if self.mode.is_single_line() {
10171            cx.propagate();
10172            return;
10173        }
10174
10175        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10176        if self.move_to_prev_snippet_tabstop(window, cx) {
10177            return;
10178        }
10179        self.outdent(&Outdent, window, cx);
10180    }
10181
10182    pub fn next_snippet_tabstop(
10183        &mut self,
10184        _: &NextSnippetTabstop,
10185        window: &mut Window,
10186        cx: &mut Context<Self>,
10187    ) {
10188        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10189            cx.propagate();
10190            return;
10191        }
10192
10193        if self.move_to_next_snippet_tabstop(window, cx) {
10194            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10195            return;
10196        }
10197        cx.propagate();
10198    }
10199
10200    pub fn previous_snippet_tabstop(
10201        &mut self,
10202        _: &PreviousSnippetTabstop,
10203        window: &mut Window,
10204        cx: &mut Context<Self>,
10205    ) {
10206        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10207            cx.propagate();
10208            return;
10209        }
10210
10211        if self.move_to_prev_snippet_tabstop(window, cx) {
10212            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10213            return;
10214        }
10215        cx.propagate();
10216    }
10217
10218    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10219        if self.mode.is_single_line() {
10220            cx.propagate();
10221            return;
10222        }
10223
10224        if self.move_to_next_snippet_tabstop(window, cx) {
10225            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10226            return;
10227        }
10228        if self.read_only(cx) {
10229            return;
10230        }
10231        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10232        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10233        let buffer = self.buffer.read(cx);
10234        let snapshot = buffer.snapshot(cx);
10235        let rows_iter = selections.iter().map(|s| s.head().row);
10236        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10237
10238        let has_some_cursor_in_whitespace = selections
10239            .iter()
10240            .filter(|selection| selection.is_empty())
10241            .any(|selection| {
10242                let cursor = selection.head();
10243                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10244                cursor.column < current_indent.len
10245            });
10246
10247        let mut edits = Vec::new();
10248        let mut prev_edited_row = 0;
10249        let mut row_delta = 0;
10250        for selection in &mut selections {
10251            if selection.start.row != prev_edited_row {
10252                row_delta = 0;
10253            }
10254            prev_edited_row = selection.end.row;
10255
10256            // If the selection is non-empty, then increase the indentation of the selected lines.
10257            if !selection.is_empty() {
10258                row_delta =
10259                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10260                continue;
10261            }
10262
10263            let cursor = selection.head();
10264            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10265            if let Some(suggested_indent) =
10266                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10267            {
10268                // Don't do anything if already at suggested indent
10269                // and there is any other cursor which is not
10270                if has_some_cursor_in_whitespace
10271                    && cursor.column == current_indent.len
10272                    && current_indent.len == suggested_indent.len
10273                {
10274                    continue;
10275                }
10276
10277                // Adjust line and move cursor to suggested indent
10278                // if cursor is not at suggested indent
10279                if cursor.column < suggested_indent.len
10280                    && cursor.column <= current_indent.len
10281                    && current_indent.len <= suggested_indent.len
10282                {
10283                    selection.start = Point::new(cursor.row, suggested_indent.len);
10284                    selection.end = selection.start;
10285                    if row_delta == 0 {
10286                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10287                            cursor.row,
10288                            current_indent,
10289                            suggested_indent,
10290                        ));
10291                        row_delta = suggested_indent.len - current_indent.len;
10292                    }
10293                    continue;
10294                }
10295
10296                // If current indent is more than suggested indent
10297                // only move cursor to current indent and skip indent
10298                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10299                    selection.start = Point::new(cursor.row, current_indent.len);
10300                    selection.end = selection.start;
10301                    continue;
10302                }
10303            }
10304
10305            // Otherwise, insert a hard or soft tab.
10306            let settings = buffer.language_settings_at(cursor, cx);
10307            let tab_size = if settings.hard_tabs {
10308                IndentSize::tab()
10309            } else {
10310                let tab_size = settings.tab_size.get();
10311                let indent_remainder = snapshot
10312                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10313                    .flat_map(str::chars)
10314                    .fold(row_delta % tab_size, |counter: u32, c| {
10315                        if c == '\t' {
10316                            0
10317                        } else {
10318                            (counter + 1) % tab_size
10319                        }
10320                    });
10321
10322                let chars_to_next_tab_stop = tab_size - indent_remainder;
10323                IndentSize::spaces(chars_to_next_tab_stop)
10324            };
10325            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10326            selection.end = selection.start;
10327            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10328            row_delta += tab_size.len;
10329        }
10330
10331        self.transact(window, cx, |this, window, cx| {
10332            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10333            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10334            this.refresh_edit_prediction(true, false, window, cx);
10335        });
10336    }
10337
10338    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10339        if self.read_only(cx) {
10340            return;
10341        }
10342        if self.mode.is_single_line() {
10343            cx.propagate();
10344            return;
10345        }
10346
10347        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10348        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10349        let mut prev_edited_row = 0;
10350        let mut row_delta = 0;
10351        let mut edits = Vec::new();
10352        let buffer = self.buffer.read(cx);
10353        let snapshot = buffer.snapshot(cx);
10354        for selection in &mut selections {
10355            if selection.start.row != prev_edited_row {
10356                row_delta = 0;
10357            }
10358            prev_edited_row = selection.end.row;
10359
10360            row_delta =
10361                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10362        }
10363
10364        self.transact(window, cx, |this, window, cx| {
10365            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10366            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10367        });
10368    }
10369
10370    fn indent_selection(
10371        buffer: &MultiBuffer,
10372        snapshot: &MultiBufferSnapshot,
10373        selection: &mut Selection<Point>,
10374        edits: &mut Vec<(Range<Point>, String)>,
10375        delta_for_start_row: u32,
10376        cx: &App,
10377    ) -> u32 {
10378        let settings = buffer.language_settings_at(selection.start, cx);
10379        let tab_size = settings.tab_size.get();
10380        let indent_kind = if settings.hard_tabs {
10381            IndentKind::Tab
10382        } else {
10383            IndentKind::Space
10384        };
10385        let mut start_row = selection.start.row;
10386        let mut end_row = selection.end.row + 1;
10387
10388        // If a selection ends at the beginning of a line, don't indent
10389        // that last line.
10390        if selection.end.column == 0 && selection.end.row > selection.start.row {
10391            end_row -= 1;
10392        }
10393
10394        // Avoid re-indenting a row that has already been indented by a
10395        // previous selection, but still update this selection's column
10396        // to reflect that indentation.
10397        if delta_for_start_row > 0 {
10398            start_row += 1;
10399            selection.start.column += delta_for_start_row;
10400            if selection.end.row == selection.start.row {
10401                selection.end.column += delta_for_start_row;
10402            }
10403        }
10404
10405        let mut delta_for_end_row = 0;
10406        let has_multiple_rows = start_row + 1 != end_row;
10407        for row in start_row..end_row {
10408            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10409            let indent_delta = match (current_indent.kind, indent_kind) {
10410                (IndentKind::Space, IndentKind::Space) => {
10411                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10412                    IndentSize::spaces(columns_to_next_tab_stop)
10413                }
10414                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10415                (_, IndentKind::Tab) => IndentSize::tab(),
10416            };
10417
10418            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10419                0
10420            } else {
10421                selection.start.column
10422            };
10423            let row_start = Point::new(row, start);
10424            edits.push((
10425                row_start..row_start,
10426                indent_delta.chars().collect::<String>(),
10427            ));
10428
10429            // Update this selection's endpoints to reflect the indentation.
10430            if row == selection.start.row {
10431                selection.start.column += indent_delta.len;
10432            }
10433            if row == selection.end.row {
10434                selection.end.column += indent_delta.len;
10435                delta_for_end_row = indent_delta.len;
10436            }
10437        }
10438
10439        if selection.start.row == selection.end.row {
10440            delta_for_start_row + delta_for_end_row
10441        } else {
10442            delta_for_end_row
10443        }
10444    }
10445
10446    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10447        if self.read_only(cx) {
10448            return;
10449        }
10450        if self.mode.is_single_line() {
10451            cx.propagate();
10452            return;
10453        }
10454
10455        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10456        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10457        let selections = self.selections.all::<Point>(&display_map);
10458        let mut deletion_ranges = Vec::new();
10459        let mut last_outdent = None;
10460        {
10461            let buffer = self.buffer.read(cx);
10462            let snapshot = buffer.snapshot(cx);
10463            for selection in &selections {
10464                let settings = buffer.language_settings_at(selection.start, cx);
10465                let tab_size = settings.tab_size.get();
10466                let mut rows = selection.spanned_rows(false, &display_map);
10467
10468                // Avoid re-outdenting a row that has already been outdented by a
10469                // previous selection.
10470                if let Some(last_row) = last_outdent
10471                    && last_row == rows.start
10472                {
10473                    rows.start = rows.start.next_row();
10474                }
10475                let has_multiple_rows = rows.len() > 1;
10476                for row in rows.iter_rows() {
10477                    let indent_size = snapshot.indent_size_for_line(row);
10478                    if indent_size.len > 0 {
10479                        let deletion_len = match indent_size.kind {
10480                            IndentKind::Space => {
10481                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10482                                if columns_to_prev_tab_stop == 0 {
10483                                    tab_size
10484                                } else {
10485                                    columns_to_prev_tab_stop
10486                                }
10487                            }
10488                            IndentKind::Tab => 1,
10489                        };
10490                        let start = if has_multiple_rows
10491                            || deletion_len > selection.start.column
10492                            || indent_size.len < selection.start.column
10493                        {
10494                            0
10495                        } else {
10496                            selection.start.column - deletion_len
10497                        };
10498                        deletion_ranges.push(
10499                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10500                        );
10501                        last_outdent = Some(row);
10502                    }
10503                }
10504            }
10505        }
10506
10507        self.transact(window, cx, |this, window, cx| {
10508            this.buffer.update(cx, |buffer, cx| {
10509                let empty_str: Arc<str> = Arc::default();
10510                buffer.edit(
10511                    deletion_ranges
10512                        .into_iter()
10513                        .map(|range| (range, empty_str.clone())),
10514                    None,
10515                    cx,
10516                );
10517            });
10518            let selections = this
10519                .selections
10520                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10521            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10522        });
10523    }
10524
10525    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10526        if self.read_only(cx) {
10527            return;
10528        }
10529        if self.mode.is_single_line() {
10530            cx.propagate();
10531            return;
10532        }
10533
10534        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10535        let selections = self
10536            .selections
10537            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10538            .into_iter()
10539            .map(|s| s.range());
10540
10541        self.transact(window, cx, |this, window, cx| {
10542            this.buffer.update(cx, |buffer, cx| {
10543                buffer.autoindent_ranges(selections, cx);
10544            });
10545            let selections = this
10546                .selections
10547                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10548            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10549        });
10550    }
10551
10552    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10553        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10554        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10555        let selections = self.selections.all::<Point>(&display_map);
10556
10557        let mut new_cursors = Vec::new();
10558        let mut edit_ranges = Vec::new();
10559        let mut selections = selections.iter().peekable();
10560        while let Some(selection) = selections.next() {
10561            let mut rows = selection.spanned_rows(false, &display_map);
10562
10563            // Accumulate contiguous regions of rows that we want to delete.
10564            while let Some(next_selection) = selections.peek() {
10565                let next_rows = next_selection.spanned_rows(false, &display_map);
10566                if next_rows.start <= rows.end {
10567                    rows.end = next_rows.end;
10568                    selections.next().unwrap();
10569                } else {
10570                    break;
10571                }
10572            }
10573
10574            let buffer = display_map.buffer_snapshot();
10575            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10576            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10577                // If there's a line after the range, delete the \n from the end of the row range
10578                (
10579                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10580                    rows.end,
10581                )
10582            } else {
10583                // If there isn't a line after the range, delete the \n from the line before the
10584                // start of the row range
10585                edit_start = edit_start.saturating_sub_usize(1);
10586                (buffer.len(), rows.start.previous_row())
10587            };
10588
10589            let text_layout_details = self.text_layout_details(window);
10590            let x = display_map.x_for_display_point(
10591                selection.head().to_display_point(&display_map),
10592                &text_layout_details,
10593            );
10594            let row = Point::new(target_row.0, 0)
10595                .to_display_point(&display_map)
10596                .row();
10597            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10598
10599            new_cursors.push((
10600                selection.id,
10601                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10602                SelectionGoal::None,
10603            ));
10604            edit_ranges.push(edit_start..edit_end);
10605        }
10606
10607        self.transact(window, cx, |this, window, cx| {
10608            let buffer = this.buffer.update(cx, |buffer, cx| {
10609                let empty_str: Arc<str> = Arc::default();
10610                buffer.edit(
10611                    edit_ranges
10612                        .into_iter()
10613                        .map(|range| (range, empty_str.clone())),
10614                    None,
10615                    cx,
10616                );
10617                buffer.snapshot(cx)
10618            });
10619            let new_selections = new_cursors
10620                .into_iter()
10621                .map(|(id, cursor, goal)| {
10622                    let cursor = cursor.to_point(&buffer);
10623                    Selection {
10624                        id,
10625                        start: cursor,
10626                        end: cursor,
10627                        reversed: false,
10628                        goal,
10629                    }
10630                })
10631                .collect();
10632
10633            this.change_selections(Default::default(), window, cx, |s| {
10634                s.select(new_selections);
10635            });
10636        });
10637    }
10638
10639    pub fn join_lines_impl(
10640        &mut self,
10641        insert_whitespace: bool,
10642        window: &mut Window,
10643        cx: &mut Context<Self>,
10644    ) {
10645        if self.read_only(cx) {
10646            return;
10647        }
10648        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10649        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10650            let start = MultiBufferRow(selection.start.row);
10651            // Treat single line selections as if they include the next line. Otherwise this action
10652            // would do nothing for single line selections individual cursors.
10653            let end = if selection.start.row == selection.end.row {
10654                MultiBufferRow(selection.start.row + 1)
10655            } else {
10656                MultiBufferRow(selection.end.row)
10657            };
10658
10659            if let Some(last_row_range) = row_ranges.last_mut()
10660                && start <= last_row_range.end
10661            {
10662                last_row_range.end = end;
10663                continue;
10664            }
10665            row_ranges.push(start..end);
10666        }
10667
10668        let snapshot = self.buffer.read(cx).snapshot(cx);
10669        let mut cursor_positions = Vec::new();
10670        for row_range in &row_ranges {
10671            let anchor = snapshot.anchor_before(Point::new(
10672                row_range.end.previous_row().0,
10673                snapshot.line_len(row_range.end.previous_row()),
10674            ));
10675            cursor_positions.push(anchor..anchor);
10676        }
10677
10678        self.transact(window, cx, |this, window, cx| {
10679            for row_range in row_ranges.into_iter().rev() {
10680                for row in row_range.iter_rows().rev() {
10681                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10682                    let next_line_row = row.next_row();
10683                    let indent = snapshot.indent_size_for_line(next_line_row);
10684                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10685
10686                    let replace =
10687                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10688                            " "
10689                        } else {
10690                            ""
10691                        };
10692
10693                    this.buffer.update(cx, |buffer, cx| {
10694                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10695                    });
10696                }
10697            }
10698
10699            this.change_selections(Default::default(), window, cx, |s| {
10700                s.select_anchor_ranges(cursor_positions)
10701            });
10702        });
10703    }
10704
10705    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10706        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10707        self.join_lines_impl(true, window, cx);
10708    }
10709
10710    pub fn sort_lines_case_sensitive(
10711        &mut self,
10712        _: &SortLinesCaseSensitive,
10713        window: &mut Window,
10714        cx: &mut Context<Self>,
10715    ) {
10716        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10717    }
10718
10719    pub fn sort_lines_by_length(
10720        &mut self,
10721        _: &SortLinesByLength,
10722        window: &mut Window,
10723        cx: &mut Context<Self>,
10724    ) {
10725        self.manipulate_immutable_lines(window, cx, |lines| {
10726            lines.sort_by_key(|&line| line.chars().count())
10727        })
10728    }
10729
10730    pub fn sort_lines_case_insensitive(
10731        &mut self,
10732        _: &SortLinesCaseInsensitive,
10733        window: &mut Window,
10734        cx: &mut Context<Self>,
10735    ) {
10736        self.manipulate_immutable_lines(window, cx, |lines| {
10737            lines.sort_by_key(|line| line.to_lowercase())
10738        })
10739    }
10740
10741    pub fn unique_lines_case_insensitive(
10742        &mut self,
10743        _: &UniqueLinesCaseInsensitive,
10744        window: &mut Window,
10745        cx: &mut Context<Self>,
10746    ) {
10747        self.manipulate_immutable_lines(window, cx, |lines| {
10748            let mut seen = HashSet::default();
10749            lines.retain(|line| seen.insert(line.to_lowercase()));
10750        })
10751    }
10752
10753    pub fn unique_lines_case_sensitive(
10754        &mut self,
10755        _: &UniqueLinesCaseSensitive,
10756        window: &mut Window,
10757        cx: &mut Context<Self>,
10758    ) {
10759        self.manipulate_immutable_lines(window, cx, |lines| {
10760            let mut seen = HashSet::default();
10761            lines.retain(|line| seen.insert(*line));
10762        })
10763    }
10764
10765    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10766        let snapshot = self.buffer.read(cx).snapshot(cx);
10767        for selection in self.selections.disjoint_anchors_arc().iter() {
10768            if snapshot
10769                .language_at(selection.start)
10770                .and_then(|lang| lang.config().wrap_characters.as_ref())
10771                .is_some()
10772            {
10773                return true;
10774            }
10775        }
10776        false
10777    }
10778
10779    fn wrap_selections_in_tag(
10780        &mut self,
10781        _: &WrapSelectionsInTag,
10782        window: &mut Window,
10783        cx: &mut Context<Self>,
10784    ) {
10785        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10786
10787        let snapshot = self.buffer.read(cx).snapshot(cx);
10788
10789        let mut edits = Vec::new();
10790        let mut boundaries = Vec::new();
10791
10792        for selection in self
10793            .selections
10794            .all_adjusted(&self.display_snapshot(cx))
10795            .iter()
10796        {
10797            let Some(wrap_config) = snapshot
10798                .language_at(selection.start)
10799                .and_then(|lang| lang.config().wrap_characters.clone())
10800            else {
10801                continue;
10802            };
10803
10804            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10805            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10806
10807            let start_before = snapshot.anchor_before(selection.start);
10808            let end_after = snapshot.anchor_after(selection.end);
10809
10810            edits.push((start_before..start_before, open_tag));
10811            edits.push((end_after..end_after, close_tag));
10812
10813            boundaries.push((
10814                start_before,
10815                end_after,
10816                wrap_config.start_prefix.len(),
10817                wrap_config.end_suffix.len(),
10818            ));
10819        }
10820
10821        if edits.is_empty() {
10822            return;
10823        }
10824
10825        self.transact(window, cx, |this, window, cx| {
10826            let buffer = this.buffer.update(cx, |buffer, cx| {
10827                buffer.edit(edits, None, cx);
10828                buffer.snapshot(cx)
10829            });
10830
10831            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10832            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10833                boundaries.into_iter()
10834            {
10835                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10836                let close_offset = end_after
10837                    .to_offset(&buffer)
10838                    .saturating_sub_usize(end_suffix_len);
10839                new_selections.push(open_offset..open_offset);
10840                new_selections.push(close_offset..close_offset);
10841            }
10842
10843            this.change_selections(Default::default(), window, cx, |s| {
10844                s.select_ranges(new_selections);
10845            });
10846
10847            this.request_autoscroll(Autoscroll::fit(), cx);
10848        });
10849    }
10850
10851    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10852        let Some(project) = self.project.clone() else {
10853            return;
10854        };
10855        self.reload(project, window, cx)
10856            .detach_and_notify_err(window, cx);
10857    }
10858
10859    pub fn restore_file(
10860        &mut self,
10861        _: &::git::RestoreFile,
10862        window: &mut Window,
10863        cx: &mut Context<Self>,
10864    ) {
10865        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10866        let mut buffer_ids = HashSet::default();
10867        let snapshot = self.buffer().read(cx).snapshot(cx);
10868        for selection in self
10869            .selections
10870            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10871        {
10872            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10873        }
10874
10875        let buffer = self.buffer().read(cx);
10876        let ranges = buffer_ids
10877            .into_iter()
10878            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10879            .collect::<Vec<_>>();
10880
10881        self.restore_hunks_in_ranges(ranges, window, cx);
10882    }
10883
10884    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10885        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10886        let selections = self
10887            .selections
10888            .all(&self.display_snapshot(cx))
10889            .into_iter()
10890            .map(|s| s.range())
10891            .collect();
10892        self.restore_hunks_in_ranges(selections, window, cx);
10893    }
10894
10895    pub fn restore_hunks_in_ranges(
10896        &mut self,
10897        ranges: Vec<Range<Point>>,
10898        window: &mut Window,
10899        cx: &mut Context<Editor>,
10900    ) {
10901        let mut revert_changes = HashMap::default();
10902        let chunk_by = self
10903            .snapshot(window, cx)
10904            .hunks_for_ranges(ranges)
10905            .into_iter()
10906            .chunk_by(|hunk| hunk.buffer_id);
10907        for (buffer_id, hunks) in &chunk_by {
10908            let hunks = hunks.collect::<Vec<_>>();
10909            for hunk in &hunks {
10910                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10911            }
10912            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10913        }
10914        drop(chunk_by);
10915        if !revert_changes.is_empty() {
10916            self.transact(window, cx, |editor, window, cx| {
10917                editor.restore(revert_changes, window, cx);
10918            });
10919        }
10920    }
10921
10922    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10923        if let Some(status) = self
10924            .addons
10925            .iter()
10926            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10927        {
10928            return Some(status);
10929        }
10930        self.project
10931            .as_ref()?
10932            .read(cx)
10933            .status_for_buffer_id(buffer_id, cx)
10934    }
10935
10936    pub fn open_active_item_in_terminal(
10937        &mut self,
10938        _: &OpenInTerminal,
10939        window: &mut Window,
10940        cx: &mut Context<Self>,
10941    ) {
10942        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10943            let project_path = buffer.read(cx).project_path(cx)?;
10944            let project = self.project()?.read(cx);
10945            let entry = project.entry_for_path(&project_path, cx)?;
10946            let parent = match &entry.canonical_path {
10947                Some(canonical_path) => canonical_path.to_path_buf(),
10948                None => project.absolute_path(&project_path, cx)?,
10949            }
10950            .parent()?
10951            .to_path_buf();
10952            Some(parent)
10953        }) {
10954            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10955        }
10956    }
10957
10958    fn set_breakpoint_context_menu(
10959        &mut self,
10960        display_row: DisplayRow,
10961        position: Option<Anchor>,
10962        clicked_point: gpui::Point<Pixels>,
10963        window: &mut Window,
10964        cx: &mut Context<Self>,
10965    ) {
10966        let source = self
10967            .buffer
10968            .read(cx)
10969            .snapshot(cx)
10970            .anchor_before(Point::new(display_row.0, 0u32));
10971
10972        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10973
10974        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10975            self,
10976            source,
10977            clicked_point,
10978            context_menu,
10979            window,
10980            cx,
10981        );
10982    }
10983
10984    fn add_edit_breakpoint_block(
10985        &mut self,
10986        anchor: Anchor,
10987        breakpoint: &Breakpoint,
10988        edit_action: BreakpointPromptEditAction,
10989        window: &mut Window,
10990        cx: &mut Context<Self>,
10991    ) {
10992        let weak_editor = cx.weak_entity();
10993        let bp_prompt = cx.new(|cx| {
10994            BreakpointPromptEditor::new(
10995                weak_editor,
10996                anchor,
10997                breakpoint.clone(),
10998                edit_action,
10999                window,
11000                cx,
11001            )
11002        });
11003
11004        let height = bp_prompt.update(cx, |this, cx| {
11005            this.prompt
11006                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11007        });
11008        let cloned_prompt = bp_prompt.clone();
11009        let blocks = vec![BlockProperties {
11010            style: BlockStyle::Sticky,
11011            placement: BlockPlacement::Above(anchor),
11012            height: Some(height),
11013            render: Arc::new(move |cx| {
11014                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11015                cloned_prompt.clone().into_any_element()
11016            }),
11017            priority: 0,
11018        }];
11019
11020        let focus_handle = bp_prompt.focus_handle(cx);
11021        window.focus(&focus_handle);
11022
11023        let block_ids = self.insert_blocks(blocks, None, cx);
11024        bp_prompt.update(cx, |prompt, _| {
11025            prompt.add_block_ids(block_ids);
11026        });
11027    }
11028
11029    pub(crate) fn breakpoint_at_row(
11030        &self,
11031        row: u32,
11032        window: &mut Window,
11033        cx: &mut Context<Self>,
11034    ) -> Option<(Anchor, Breakpoint)> {
11035        let snapshot = self.snapshot(window, cx);
11036        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11037
11038        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11039    }
11040
11041    pub(crate) fn breakpoint_at_anchor(
11042        &self,
11043        breakpoint_position: Anchor,
11044        snapshot: &EditorSnapshot,
11045        cx: &mut Context<Self>,
11046    ) -> Option<(Anchor, Breakpoint)> {
11047        let buffer = self
11048            .buffer
11049            .read(cx)
11050            .buffer_for_anchor(breakpoint_position, cx)?;
11051
11052        let enclosing_excerpt = breakpoint_position.excerpt_id;
11053        let buffer_snapshot = buffer.read(cx).snapshot();
11054
11055        let row = buffer_snapshot
11056            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11057            .row;
11058
11059        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11060        let anchor_end = snapshot
11061            .buffer_snapshot()
11062            .anchor_after(Point::new(row, line_len));
11063
11064        self.breakpoint_store
11065            .as_ref()?
11066            .read_with(cx, |breakpoint_store, cx| {
11067                breakpoint_store
11068                    .breakpoints(
11069                        &buffer,
11070                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11071                        &buffer_snapshot,
11072                        cx,
11073                    )
11074                    .next()
11075                    .and_then(|(bp, _)| {
11076                        let breakpoint_row = buffer_snapshot
11077                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11078                            .row;
11079
11080                        if breakpoint_row == row {
11081                            snapshot
11082                                .buffer_snapshot()
11083                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11084                                .map(|position| (position, bp.bp.clone()))
11085                        } else {
11086                            None
11087                        }
11088                    })
11089            })
11090    }
11091
11092    pub fn edit_log_breakpoint(
11093        &mut self,
11094        _: &EditLogBreakpoint,
11095        window: &mut Window,
11096        cx: &mut Context<Self>,
11097    ) {
11098        if self.breakpoint_store.is_none() {
11099            return;
11100        }
11101
11102        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11103            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11104                message: None,
11105                state: BreakpointState::Enabled,
11106                condition: None,
11107                hit_condition: None,
11108            });
11109
11110            self.add_edit_breakpoint_block(
11111                anchor,
11112                &breakpoint,
11113                BreakpointPromptEditAction::Log,
11114                window,
11115                cx,
11116            );
11117        }
11118    }
11119
11120    fn breakpoints_at_cursors(
11121        &self,
11122        window: &mut Window,
11123        cx: &mut Context<Self>,
11124    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11125        let snapshot = self.snapshot(window, cx);
11126        let cursors = self
11127            .selections
11128            .disjoint_anchors_arc()
11129            .iter()
11130            .map(|selection| {
11131                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11132
11133                let breakpoint_position = self
11134                    .breakpoint_at_row(cursor_position.row, window, cx)
11135                    .map(|bp| bp.0)
11136                    .unwrap_or_else(|| {
11137                        snapshot
11138                            .display_snapshot
11139                            .buffer_snapshot()
11140                            .anchor_after(Point::new(cursor_position.row, 0))
11141                    });
11142
11143                let breakpoint = self
11144                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11145                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11146
11147                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11148            })
11149            // 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.
11150            .collect::<HashMap<Anchor, _>>();
11151
11152        cursors.into_iter().collect()
11153    }
11154
11155    pub fn enable_breakpoint(
11156        &mut self,
11157        _: &crate::actions::EnableBreakpoint,
11158        window: &mut Window,
11159        cx: &mut Context<Self>,
11160    ) {
11161        if self.breakpoint_store.is_none() {
11162            return;
11163        }
11164
11165        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11166            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11167                continue;
11168            };
11169            self.edit_breakpoint_at_anchor(
11170                anchor,
11171                breakpoint,
11172                BreakpointEditAction::InvertState,
11173                cx,
11174            );
11175        }
11176    }
11177
11178    pub fn disable_breakpoint(
11179        &mut self,
11180        _: &crate::actions::DisableBreakpoint,
11181        window: &mut Window,
11182        cx: &mut Context<Self>,
11183    ) {
11184        if self.breakpoint_store.is_none() {
11185            return;
11186        }
11187
11188        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11189            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11190                continue;
11191            };
11192            self.edit_breakpoint_at_anchor(
11193                anchor,
11194                breakpoint,
11195                BreakpointEditAction::InvertState,
11196                cx,
11197            );
11198        }
11199    }
11200
11201    pub fn toggle_breakpoint(
11202        &mut self,
11203        _: &crate::actions::ToggleBreakpoint,
11204        window: &mut Window,
11205        cx: &mut Context<Self>,
11206    ) {
11207        if self.breakpoint_store.is_none() {
11208            return;
11209        }
11210
11211        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11212            if let Some(breakpoint) = breakpoint {
11213                self.edit_breakpoint_at_anchor(
11214                    anchor,
11215                    breakpoint,
11216                    BreakpointEditAction::Toggle,
11217                    cx,
11218                );
11219            } else {
11220                self.edit_breakpoint_at_anchor(
11221                    anchor,
11222                    Breakpoint::new_standard(),
11223                    BreakpointEditAction::Toggle,
11224                    cx,
11225                );
11226            }
11227        }
11228    }
11229
11230    pub fn edit_breakpoint_at_anchor(
11231        &mut self,
11232        breakpoint_position: Anchor,
11233        breakpoint: Breakpoint,
11234        edit_action: BreakpointEditAction,
11235        cx: &mut Context<Self>,
11236    ) {
11237        let Some(breakpoint_store) = &self.breakpoint_store else {
11238            return;
11239        };
11240
11241        let Some(buffer) = self
11242            .buffer
11243            .read(cx)
11244            .buffer_for_anchor(breakpoint_position, cx)
11245        else {
11246            return;
11247        };
11248
11249        breakpoint_store.update(cx, |breakpoint_store, cx| {
11250            breakpoint_store.toggle_breakpoint(
11251                buffer,
11252                BreakpointWithPosition {
11253                    position: breakpoint_position.text_anchor,
11254                    bp: breakpoint,
11255                },
11256                edit_action,
11257                cx,
11258            );
11259        });
11260
11261        cx.notify();
11262    }
11263
11264    #[cfg(any(test, feature = "test-support"))]
11265    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11266        self.breakpoint_store.clone()
11267    }
11268
11269    pub fn prepare_restore_change(
11270        &self,
11271        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11272        hunk: &MultiBufferDiffHunk,
11273        cx: &mut App,
11274    ) -> Option<()> {
11275        if hunk.is_created_file() {
11276            return None;
11277        }
11278        let buffer = self.buffer.read(cx);
11279        let diff = buffer.diff_for(hunk.buffer_id)?;
11280        let buffer = buffer.buffer(hunk.buffer_id)?;
11281        let buffer = buffer.read(cx);
11282        let original_text = diff
11283            .read(cx)
11284            .base_text()
11285            .as_rope()
11286            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11287        let buffer_snapshot = buffer.snapshot();
11288        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11289        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11290            probe
11291                .0
11292                .start
11293                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11294                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11295        }) {
11296            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11297            Some(())
11298        } else {
11299            None
11300        }
11301    }
11302
11303    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11304        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11305    }
11306
11307    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11308        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11309    }
11310
11311    fn manipulate_lines<M>(
11312        &mut self,
11313        window: &mut Window,
11314        cx: &mut Context<Self>,
11315        mut manipulate: M,
11316    ) where
11317        M: FnMut(&str) -> LineManipulationResult,
11318    {
11319        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11320
11321        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11322        let buffer = self.buffer.read(cx).snapshot(cx);
11323
11324        let mut edits = Vec::new();
11325
11326        let selections = self.selections.all::<Point>(&display_map);
11327        let mut selections = selections.iter().peekable();
11328        let mut contiguous_row_selections = Vec::new();
11329        let mut new_selections = Vec::new();
11330        let mut added_lines = 0;
11331        let mut removed_lines = 0;
11332
11333        while let Some(selection) = selections.next() {
11334            let (start_row, end_row) = consume_contiguous_rows(
11335                &mut contiguous_row_selections,
11336                selection,
11337                &display_map,
11338                &mut selections,
11339            );
11340
11341            let start_point = Point::new(start_row.0, 0);
11342            let end_point = Point::new(
11343                end_row.previous_row().0,
11344                buffer.line_len(end_row.previous_row()),
11345            );
11346            let text = buffer
11347                .text_for_range(start_point..end_point)
11348                .collect::<String>();
11349
11350            let LineManipulationResult {
11351                new_text,
11352                line_count_before,
11353                line_count_after,
11354            } = manipulate(&text);
11355
11356            edits.push((start_point..end_point, new_text));
11357
11358            // Selections must change based on added and removed line count
11359            let start_row =
11360                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11361            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11362            new_selections.push(Selection {
11363                id: selection.id,
11364                start: start_row,
11365                end: end_row,
11366                goal: SelectionGoal::None,
11367                reversed: selection.reversed,
11368            });
11369
11370            if line_count_after > line_count_before {
11371                added_lines += line_count_after - line_count_before;
11372            } else if line_count_before > line_count_after {
11373                removed_lines += line_count_before - line_count_after;
11374            }
11375        }
11376
11377        self.transact(window, cx, |this, window, cx| {
11378            let buffer = this.buffer.update(cx, |buffer, cx| {
11379                buffer.edit(edits, None, cx);
11380                buffer.snapshot(cx)
11381            });
11382
11383            // Recalculate offsets on newly edited buffer
11384            let new_selections = new_selections
11385                .iter()
11386                .map(|s| {
11387                    let start_point = Point::new(s.start.0, 0);
11388                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11389                    Selection {
11390                        id: s.id,
11391                        start: buffer.point_to_offset(start_point),
11392                        end: buffer.point_to_offset(end_point),
11393                        goal: s.goal,
11394                        reversed: s.reversed,
11395                    }
11396                })
11397                .collect();
11398
11399            this.change_selections(Default::default(), window, cx, |s| {
11400                s.select(new_selections);
11401            });
11402
11403            this.request_autoscroll(Autoscroll::fit(), cx);
11404        });
11405    }
11406
11407    fn manipulate_immutable_lines<Fn>(
11408        &mut self,
11409        window: &mut Window,
11410        cx: &mut Context<Self>,
11411        mut callback: Fn,
11412    ) where
11413        Fn: FnMut(&mut Vec<&str>),
11414    {
11415        self.manipulate_lines(window, cx, |text| {
11416            let mut lines: Vec<&str> = text.split('\n').collect();
11417            let line_count_before = lines.len();
11418
11419            callback(&mut lines);
11420
11421            LineManipulationResult {
11422                new_text: lines.join("\n"),
11423                line_count_before,
11424                line_count_after: lines.len(),
11425            }
11426        });
11427    }
11428
11429    fn manipulate_mutable_lines<Fn>(
11430        &mut self,
11431        window: &mut Window,
11432        cx: &mut Context<Self>,
11433        mut callback: Fn,
11434    ) where
11435        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11436    {
11437        self.manipulate_lines(window, cx, |text| {
11438            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11439            let line_count_before = lines.len();
11440
11441            callback(&mut lines);
11442
11443            LineManipulationResult {
11444                new_text: lines.join("\n"),
11445                line_count_before,
11446                line_count_after: lines.len(),
11447            }
11448        });
11449    }
11450
11451    pub fn convert_indentation_to_spaces(
11452        &mut self,
11453        _: &ConvertIndentationToSpaces,
11454        window: &mut Window,
11455        cx: &mut Context<Self>,
11456    ) {
11457        let settings = self.buffer.read(cx).language_settings(cx);
11458        let tab_size = settings.tab_size.get() as usize;
11459
11460        self.manipulate_mutable_lines(window, cx, |lines| {
11461            // Allocates a reasonably sized scratch buffer once for the whole loop
11462            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11463            // Avoids recomputing spaces that could be inserted many times
11464            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11465                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11466                .collect();
11467
11468            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11469                let mut chars = line.as_ref().chars();
11470                let mut col = 0;
11471                let mut changed = false;
11472
11473                for ch in chars.by_ref() {
11474                    match ch {
11475                        ' ' => {
11476                            reindented_line.push(' ');
11477                            col += 1;
11478                        }
11479                        '\t' => {
11480                            // \t are converted to spaces depending on the current column
11481                            let spaces_len = tab_size - (col % tab_size);
11482                            reindented_line.extend(&space_cache[spaces_len - 1]);
11483                            col += spaces_len;
11484                            changed = true;
11485                        }
11486                        _ => {
11487                            // If we dont append before break, the character is consumed
11488                            reindented_line.push(ch);
11489                            break;
11490                        }
11491                    }
11492                }
11493
11494                if !changed {
11495                    reindented_line.clear();
11496                    continue;
11497                }
11498                // Append the rest of the line and replace old reference with new one
11499                reindented_line.extend(chars);
11500                *line = Cow::Owned(reindented_line.clone());
11501                reindented_line.clear();
11502            }
11503        });
11504    }
11505
11506    pub fn convert_indentation_to_tabs(
11507        &mut self,
11508        _: &ConvertIndentationToTabs,
11509        window: &mut Window,
11510        cx: &mut Context<Self>,
11511    ) {
11512        let settings = self.buffer.read(cx).language_settings(cx);
11513        let tab_size = settings.tab_size.get() as usize;
11514
11515        self.manipulate_mutable_lines(window, cx, |lines| {
11516            // Allocates a reasonably sized buffer once for the whole loop
11517            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11518            // Avoids recomputing spaces that could be inserted many times
11519            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11520                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11521                .collect();
11522
11523            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11524                let mut chars = line.chars();
11525                let mut spaces_count = 0;
11526                let mut first_non_indent_char = None;
11527                let mut changed = false;
11528
11529                for ch in chars.by_ref() {
11530                    match ch {
11531                        ' ' => {
11532                            // Keep track of spaces. Append \t when we reach tab_size
11533                            spaces_count += 1;
11534                            changed = true;
11535                            if spaces_count == tab_size {
11536                                reindented_line.push('\t');
11537                                spaces_count = 0;
11538                            }
11539                        }
11540                        '\t' => {
11541                            reindented_line.push('\t');
11542                            spaces_count = 0;
11543                        }
11544                        _ => {
11545                            // Dont append it yet, we might have remaining spaces
11546                            first_non_indent_char = Some(ch);
11547                            break;
11548                        }
11549                    }
11550                }
11551
11552                if !changed {
11553                    reindented_line.clear();
11554                    continue;
11555                }
11556                // Remaining spaces that didn't make a full tab stop
11557                if spaces_count > 0 {
11558                    reindented_line.extend(&space_cache[spaces_count - 1]);
11559                }
11560                // If we consume an extra character that was not indentation, add it back
11561                if let Some(extra_char) = first_non_indent_char {
11562                    reindented_line.push(extra_char);
11563                }
11564                // Append the rest of the line and replace old reference with new one
11565                reindented_line.extend(chars);
11566                *line = Cow::Owned(reindented_line.clone());
11567                reindented_line.clear();
11568            }
11569        });
11570    }
11571
11572    pub fn convert_to_upper_case(
11573        &mut self,
11574        _: &ConvertToUpperCase,
11575        window: &mut Window,
11576        cx: &mut Context<Self>,
11577    ) {
11578        self.manipulate_text(window, cx, |text| text.to_uppercase())
11579    }
11580
11581    pub fn convert_to_lower_case(
11582        &mut self,
11583        _: &ConvertToLowerCase,
11584        window: &mut Window,
11585        cx: &mut Context<Self>,
11586    ) {
11587        self.manipulate_text(window, cx, |text| text.to_lowercase())
11588    }
11589
11590    pub fn convert_to_title_case(
11591        &mut self,
11592        _: &ConvertToTitleCase,
11593        window: &mut Window,
11594        cx: &mut Context<Self>,
11595    ) {
11596        self.manipulate_text(window, cx, |text| {
11597            text.split('\n')
11598                .map(|line| line.to_case(Case::Title))
11599                .join("\n")
11600        })
11601    }
11602
11603    pub fn convert_to_snake_case(
11604        &mut self,
11605        _: &ConvertToSnakeCase,
11606        window: &mut Window,
11607        cx: &mut Context<Self>,
11608    ) {
11609        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11610    }
11611
11612    pub fn convert_to_kebab_case(
11613        &mut self,
11614        _: &ConvertToKebabCase,
11615        window: &mut Window,
11616        cx: &mut Context<Self>,
11617    ) {
11618        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11619    }
11620
11621    pub fn convert_to_upper_camel_case(
11622        &mut self,
11623        _: &ConvertToUpperCamelCase,
11624        window: &mut Window,
11625        cx: &mut Context<Self>,
11626    ) {
11627        self.manipulate_text(window, cx, |text| {
11628            text.split('\n')
11629                .map(|line| line.to_case(Case::UpperCamel))
11630                .join("\n")
11631        })
11632    }
11633
11634    pub fn convert_to_lower_camel_case(
11635        &mut self,
11636        _: &ConvertToLowerCamelCase,
11637        window: &mut Window,
11638        cx: &mut Context<Self>,
11639    ) {
11640        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11641    }
11642
11643    pub fn convert_to_opposite_case(
11644        &mut self,
11645        _: &ConvertToOppositeCase,
11646        window: &mut Window,
11647        cx: &mut Context<Self>,
11648    ) {
11649        self.manipulate_text(window, cx, |text| {
11650            text.chars()
11651                .fold(String::with_capacity(text.len()), |mut t, c| {
11652                    if c.is_uppercase() {
11653                        t.extend(c.to_lowercase());
11654                    } else {
11655                        t.extend(c.to_uppercase());
11656                    }
11657                    t
11658                })
11659        })
11660    }
11661
11662    pub fn convert_to_sentence_case(
11663        &mut self,
11664        _: &ConvertToSentenceCase,
11665        window: &mut Window,
11666        cx: &mut Context<Self>,
11667    ) {
11668        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11669    }
11670
11671    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11672        self.manipulate_text(window, cx, |text| {
11673            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11674            if has_upper_case_characters {
11675                text.to_lowercase()
11676            } else {
11677                text.to_uppercase()
11678            }
11679        })
11680    }
11681
11682    pub fn convert_to_rot13(
11683        &mut self,
11684        _: &ConvertToRot13,
11685        window: &mut Window,
11686        cx: &mut Context<Self>,
11687    ) {
11688        self.manipulate_text(window, cx, |text| {
11689            text.chars()
11690                .map(|c| match c {
11691                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11692                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11693                    _ => c,
11694                })
11695                .collect()
11696        })
11697    }
11698
11699    pub fn convert_to_rot47(
11700        &mut self,
11701        _: &ConvertToRot47,
11702        window: &mut Window,
11703        cx: &mut Context<Self>,
11704    ) {
11705        self.manipulate_text(window, cx, |text| {
11706            text.chars()
11707                .map(|c| {
11708                    let code_point = c as u32;
11709                    if code_point >= 33 && code_point <= 126 {
11710                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11711                    }
11712                    c
11713                })
11714                .collect()
11715        })
11716    }
11717
11718    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11719    where
11720        Fn: FnMut(&str) -> String,
11721    {
11722        let buffer = self.buffer.read(cx).snapshot(cx);
11723
11724        let mut new_selections = Vec::new();
11725        let mut edits = Vec::new();
11726        let mut selection_adjustment = 0isize;
11727
11728        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11729            let selection_is_empty = selection.is_empty();
11730
11731            let (start, end) = if selection_is_empty {
11732                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11733                (word_range.start, word_range.end)
11734            } else {
11735                (
11736                    buffer.point_to_offset(selection.start),
11737                    buffer.point_to_offset(selection.end),
11738                )
11739            };
11740
11741            let text = buffer.text_for_range(start..end).collect::<String>();
11742            let old_length = text.len() as isize;
11743            let text = callback(&text);
11744
11745            new_selections.push(Selection {
11746                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
11747                end: MultiBufferOffset(
11748                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
11749                ),
11750                goal: SelectionGoal::None,
11751                id: selection.id,
11752                reversed: selection.reversed,
11753            });
11754
11755            selection_adjustment += old_length - text.len() as isize;
11756
11757            edits.push((start..end, text));
11758        }
11759
11760        self.transact(window, cx, |this, window, cx| {
11761            this.buffer.update(cx, |buffer, cx| {
11762                buffer.edit(edits, None, cx);
11763            });
11764
11765            this.change_selections(Default::default(), window, cx, |s| {
11766                s.select(new_selections);
11767            });
11768
11769            this.request_autoscroll(Autoscroll::fit(), cx);
11770        });
11771    }
11772
11773    pub fn move_selection_on_drop(
11774        &mut self,
11775        selection: &Selection<Anchor>,
11776        target: DisplayPoint,
11777        is_cut: bool,
11778        window: &mut Window,
11779        cx: &mut Context<Self>,
11780    ) {
11781        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11782        let buffer = display_map.buffer_snapshot();
11783        let mut edits = Vec::new();
11784        let insert_point = display_map
11785            .clip_point(target, Bias::Left)
11786            .to_point(&display_map);
11787        let text = buffer
11788            .text_for_range(selection.start..selection.end)
11789            .collect::<String>();
11790        if is_cut {
11791            edits.push(((selection.start..selection.end), String::new()));
11792        }
11793        let insert_anchor = buffer.anchor_before(insert_point);
11794        edits.push(((insert_anchor..insert_anchor), text));
11795        let last_edit_start = insert_anchor.bias_left(buffer);
11796        let last_edit_end = insert_anchor.bias_right(buffer);
11797        self.transact(window, cx, |this, window, cx| {
11798            this.buffer.update(cx, |buffer, cx| {
11799                buffer.edit(edits, None, cx);
11800            });
11801            this.change_selections(Default::default(), window, cx, |s| {
11802                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11803            });
11804        });
11805    }
11806
11807    pub fn clear_selection_drag_state(&mut self) {
11808        self.selection_drag_state = SelectionDragState::None;
11809    }
11810
11811    pub fn duplicate(
11812        &mut self,
11813        upwards: bool,
11814        whole_lines: bool,
11815        window: &mut Window,
11816        cx: &mut Context<Self>,
11817    ) {
11818        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11819
11820        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11821        let buffer = display_map.buffer_snapshot();
11822        let selections = self.selections.all::<Point>(&display_map);
11823
11824        let mut edits = Vec::new();
11825        let mut selections_iter = selections.iter().peekable();
11826        while let Some(selection) = selections_iter.next() {
11827            let mut rows = selection.spanned_rows(false, &display_map);
11828            // duplicate line-wise
11829            if whole_lines || selection.start == selection.end {
11830                // Avoid duplicating the same lines twice.
11831                while let Some(next_selection) = selections_iter.peek() {
11832                    let next_rows = next_selection.spanned_rows(false, &display_map);
11833                    if next_rows.start < rows.end {
11834                        rows.end = next_rows.end;
11835                        selections_iter.next().unwrap();
11836                    } else {
11837                        break;
11838                    }
11839                }
11840
11841                // Copy the text from the selected row region and splice it either at the start
11842                // or end of the region.
11843                let start = Point::new(rows.start.0, 0);
11844                let end = Point::new(
11845                    rows.end.previous_row().0,
11846                    buffer.line_len(rows.end.previous_row()),
11847                );
11848
11849                let mut text = buffer.text_for_range(start..end).collect::<String>();
11850
11851                let insert_location = if upwards {
11852                    // When duplicating upward, we need to insert before the current line.
11853                    // If we're on the last line and it doesn't end with a newline,
11854                    // we need to add a newline before the duplicated content.
11855                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11856                        && buffer.max_point().column > 0
11857                        && !text.ends_with('\n');
11858
11859                    if needs_leading_newline {
11860                        text.insert(0, '\n');
11861                        end
11862                    } else {
11863                        text.push('\n');
11864                        Point::new(rows.start.0, 0)
11865                    }
11866                } else {
11867                    text.push('\n');
11868                    start
11869                };
11870                edits.push((insert_location..insert_location, text));
11871            } else {
11872                // duplicate character-wise
11873                let start = selection.start;
11874                let end = selection.end;
11875                let text = buffer.text_for_range(start..end).collect::<String>();
11876                edits.push((selection.end..selection.end, text));
11877            }
11878        }
11879
11880        self.transact(window, cx, |this, window, cx| {
11881            this.buffer.update(cx, |buffer, cx| {
11882                buffer.edit(edits, None, cx);
11883            });
11884
11885            // When duplicating upward with whole lines, move the cursor to the duplicated line
11886            if upwards && whole_lines {
11887                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11888
11889                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11890                    let mut new_ranges = Vec::new();
11891                    let selections = s.all::<Point>(&display_map);
11892                    let mut selections_iter = selections.iter().peekable();
11893
11894                    while let Some(first_selection) = selections_iter.next() {
11895                        // Group contiguous selections together to find the total row span
11896                        let mut group_selections = vec![first_selection];
11897                        let mut rows = first_selection.spanned_rows(false, &display_map);
11898
11899                        while let Some(next_selection) = selections_iter.peek() {
11900                            let next_rows = next_selection.spanned_rows(false, &display_map);
11901                            if next_rows.start < rows.end {
11902                                rows.end = next_rows.end;
11903                                group_selections.push(selections_iter.next().unwrap());
11904                            } else {
11905                                break;
11906                            }
11907                        }
11908
11909                        let row_count = rows.end.0 - rows.start.0;
11910
11911                        // Move all selections in this group up by the total number of duplicated rows
11912                        for selection in group_selections {
11913                            let new_start = Point::new(
11914                                selection.start.row.saturating_sub(row_count),
11915                                selection.start.column,
11916                            );
11917
11918                            let new_end = Point::new(
11919                                selection.end.row.saturating_sub(row_count),
11920                                selection.end.column,
11921                            );
11922
11923                            new_ranges.push(new_start..new_end);
11924                        }
11925                    }
11926
11927                    s.select_ranges(new_ranges);
11928                });
11929            }
11930
11931            this.request_autoscroll(Autoscroll::fit(), cx);
11932        });
11933    }
11934
11935    pub fn duplicate_line_up(
11936        &mut self,
11937        _: &DuplicateLineUp,
11938        window: &mut Window,
11939        cx: &mut Context<Self>,
11940    ) {
11941        self.duplicate(true, true, window, cx);
11942    }
11943
11944    pub fn duplicate_line_down(
11945        &mut self,
11946        _: &DuplicateLineDown,
11947        window: &mut Window,
11948        cx: &mut Context<Self>,
11949    ) {
11950        self.duplicate(false, true, window, cx);
11951    }
11952
11953    pub fn duplicate_selection(
11954        &mut self,
11955        _: &DuplicateSelection,
11956        window: &mut Window,
11957        cx: &mut Context<Self>,
11958    ) {
11959        self.duplicate(false, false, window, cx);
11960    }
11961
11962    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11963        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11964        if self.mode.is_single_line() {
11965            cx.propagate();
11966            return;
11967        }
11968
11969        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11970        let buffer = self.buffer.read(cx).snapshot(cx);
11971
11972        let mut edits = Vec::new();
11973        let mut unfold_ranges = Vec::new();
11974        let mut refold_creases = Vec::new();
11975
11976        let selections = self.selections.all::<Point>(&display_map);
11977        let mut selections = selections.iter().peekable();
11978        let mut contiguous_row_selections = Vec::new();
11979        let mut new_selections = Vec::new();
11980
11981        while let Some(selection) = selections.next() {
11982            // Find all the selections that span a contiguous row range
11983            let (start_row, end_row) = consume_contiguous_rows(
11984                &mut contiguous_row_selections,
11985                selection,
11986                &display_map,
11987                &mut selections,
11988            );
11989
11990            // Move the text spanned by the row range to be before the line preceding the row range
11991            if start_row.0 > 0 {
11992                let range_to_move = Point::new(
11993                    start_row.previous_row().0,
11994                    buffer.line_len(start_row.previous_row()),
11995                )
11996                    ..Point::new(
11997                        end_row.previous_row().0,
11998                        buffer.line_len(end_row.previous_row()),
11999                    );
12000                let insertion_point = display_map
12001                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12002                    .0;
12003
12004                // Don't move lines across excerpts
12005                if buffer
12006                    .excerpt_containing(insertion_point..range_to_move.end)
12007                    .is_some()
12008                {
12009                    let text = buffer
12010                        .text_for_range(range_to_move.clone())
12011                        .flat_map(|s| s.chars())
12012                        .skip(1)
12013                        .chain(['\n'])
12014                        .collect::<String>();
12015
12016                    edits.push((
12017                        buffer.anchor_after(range_to_move.start)
12018                            ..buffer.anchor_before(range_to_move.end),
12019                        String::new(),
12020                    ));
12021                    let insertion_anchor = buffer.anchor_after(insertion_point);
12022                    edits.push((insertion_anchor..insertion_anchor, text));
12023
12024                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12025
12026                    // Move selections up
12027                    new_selections.extend(contiguous_row_selections.drain(..).map(
12028                        |mut selection| {
12029                            selection.start.row -= row_delta;
12030                            selection.end.row -= row_delta;
12031                            selection
12032                        },
12033                    ));
12034
12035                    // Move folds up
12036                    unfold_ranges.push(range_to_move.clone());
12037                    for fold in display_map.folds_in_range(
12038                        buffer.anchor_before(range_to_move.start)
12039                            ..buffer.anchor_after(range_to_move.end),
12040                    ) {
12041                        let mut start = fold.range.start.to_point(&buffer);
12042                        let mut end = fold.range.end.to_point(&buffer);
12043                        start.row -= row_delta;
12044                        end.row -= row_delta;
12045                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12046                    }
12047                }
12048            }
12049
12050            // If we didn't move line(s), preserve the existing selections
12051            new_selections.append(&mut contiguous_row_selections);
12052        }
12053
12054        self.transact(window, cx, |this, window, cx| {
12055            this.unfold_ranges(&unfold_ranges, true, true, cx);
12056            this.buffer.update(cx, |buffer, cx| {
12057                for (range, text) in edits {
12058                    buffer.edit([(range, text)], None, cx);
12059                }
12060            });
12061            this.fold_creases(refold_creases, true, window, cx);
12062            this.change_selections(Default::default(), window, cx, |s| {
12063                s.select(new_selections);
12064            })
12065        });
12066    }
12067
12068    pub fn move_line_down(
12069        &mut self,
12070        _: &MoveLineDown,
12071        window: &mut Window,
12072        cx: &mut Context<Self>,
12073    ) {
12074        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12075        if self.mode.is_single_line() {
12076            cx.propagate();
12077            return;
12078        }
12079
12080        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12081        let buffer = self.buffer.read(cx).snapshot(cx);
12082
12083        let mut edits = Vec::new();
12084        let mut unfold_ranges = Vec::new();
12085        let mut refold_creases = Vec::new();
12086
12087        let selections = self.selections.all::<Point>(&display_map);
12088        let mut selections = selections.iter().peekable();
12089        let mut contiguous_row_selections = Vec::new();
12090        let mut new_selections = Vec::new();
12091
12092        while let Some(selection) = selections.next() {
12093            // Find all the selections that span a contiguous row range
12094            let (start_row, end_row) = consume_contiguous_rows(
12095                &mut contiguous_row_selections,
12096                selection,
12097                &display_map,
12098                &mut selections,
12099            );
12100
12101            // Move the text spanned by the row range to be after the last line of the row range
12102            if end_row.0 <= buffer.max_point().row {
12103                let range_to_move =
12104                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12105                let insertion_point = display_map
12106                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12107                    .0;
12108
12109                // Don't move lines across excerpt boundaries
12110                if buffer
12111                    .excerpt_containing(range_to_move.start..insertion_point)
12112                    .is_some()
12113                {
12114                    let mut text = String::from("\n");
12115                    text.extend(buffer.text_for_range(range_to_move.clone()));
12116                    text.pop(); // Drop trailing newline
12117                    edits.push((
12118                        buffer.anchor_after(range_to_move.start)
12119                            ..buffer.anchor_before(range_to_move.end),
12120                        String::new(),
12121                    ));
12122                    let insertion_anchor = buffer.anchor_after(insertion_point);
12123                    edits.push((insertion_anchor..insertion_anchor, text));
12124
12125                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12126
12127                    // Move selections down
12128                    new_selections.extend(contiguous_row_selections.drain(..).map(
12129                        |mut selection| {
12130                            selection.start.row += row_delta;
12131                            selection.end.row += row_delta;
12132                            selection
12133                        },
12134                    ));
12135
12136                    // Move folds down
12137                    unfold_ranges.push(range_to_move.clone());
12138                    for fold in display_map.folds_in_range(
12139                        buffer.anchor_before(range_to_move.start)
12140                            ..buffer.anchor_after(range_to_move.end),
12141                    ) {
12142                        let mut start = fold.range.start.to_point(&buffer);
12143                        let mut end = fold.range.end.to_point(&buffer);
12144                        start.row += row_delta;
12145                        end.row += row_delta;
12146                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12147                    }
12148                }
12149            }
12150
12151            // If we didn't move line(s), preserve the existing selections
12152            new_selections.append(&mut contiguous_row_selections);
12153        }
12154
12155        self.transact(window, cx, |this, window, cx| {
12156            this.unfold_ranges(&unfold_ranges, true, true, cx);
12157            this.buffer.update(cx, |buffer, cx| {
12158                for (range, text) in edits {
12159                    buffer.edit([(range, text)], None, cx);
12160                }
12161            });
12162            this.fold_creases(refold_creases, true, window, cx);
12163            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12164        });
12165    }
12166
12167    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12168        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12169        let text_layout_details = &self.text_layout_details(window);
12170        self.transact(window, cx, |this, window, cx| {
12171            let edits = this.change_selections(Default::default(), window, cx, |s| {
12172                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12173                s.move_with(|display_map, selection| {
12174                    if !selection.is_empty() {
12175                        return;
12176                    }
12177
12178                    let mut head = selection.head();
12179                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12180                    if head.column() == display_map.line_len(head.row()) {
12181                        transpose_offset = display_map
12182                            .buffer_snapshot()
12183                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12184                    }
12185
12186                    if transpose_offset == MultiBufferOffset(0) {
12187                        return;
12188                    }
12189
12190                    *head.column_mut() += 1;
12191                    head = display_map.clip_point(head, Bias::Right);
12192                    let goal = SelectionGoal::HorizontalPosition(
12193                        display_map
12194                            .x_for_display_point(head, text_layout_details)
12195                            .into(),
12196                    );
12197                    selection.collapse_to(head, goal);
12198
12199                    let transpose_start = display_map
12200                        .buffer_snapshot()
12201                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12202                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12203                        let transpose_end = display_map
12204                            .buffer_snapshot()
12205                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12206                        if let Some(ch) = display_map
12207                            .buffer_snapshot()
12208                            .chars_at(transpose_start)
12209                            .next()
12210                        {
12211                            edits.push((transpose_start..transpose_offset, String::new()));
12212                            edits.push((transpose_end..transpose_end, ch.to_string()));
12213                        }
12214                    }
12215                });
12216                edits
12217            });
12218            this.buffer
12219                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12220            let selections = this
12221                .selections
12222                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12223            this.change_selections(Default::default(), window, cx, |s| {
12224                s.select(selections);
12225            });
12226        });
12227    }
12228
12229    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12230        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12231        if self.mode.is_single_line() {
12232            cx.propagate();
12233            return;
12234        }
12235
12236        self.rewrap_impl(RewrapOptions::default(), cx)
12237    }
12238
12239    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12240        let buffer = self.buffer.read(cx).snapshot(cx);
12241        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12242
12243        #[derive(Clone, Debug, PartialEq)]
12244        enum CommentFormat {
12245            /// single line comment, with prefix for line
12246            Line(String),
12247            /// single line within a block comment, with prefix for line
12248            BlockLine(String),
12249            /// a single line of a block comment that includes the initial delimiter
12250            BlockCommentWithStart(BlockCommentConfig),
12251            /// a single line of a block comment that includes the ending delimiter
12252            BlockCommentWithEnd(BlockCommentConfig),
12253        }
12254
12255        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12256        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12257            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12258                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12259                .peekable();
12260
12261            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12262                row
12263            } else {
12264                return Vec::new();
12265            };
12266
12267            let language_settings = buffer.language_settings_at(selection.head(), cx);
12268            let language_scope = buffer.language_scope_at(selection.head());
12269
12270            let indent_and_prefix_for_row =
12271                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12272                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12273                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12274                        &language_scope
12275                    {
12276                        let indent_end = Point::new(row, indent.len);
12277                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12278                        let line_text_after_indent = buffer
12279                            .text_for_range(indent_end..line_end)
12280                            .collect::<String>();
12281
12282                        let is_within_comment_override = buffer
12283                            .language_scope_at(indent_end)
12284                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12285                        let comment_delimiters = if is_within_comment_override {
12286                            // we are within a comment syntax node, but we don't
12287                            // yet know what kind of comment: block, doc or line
12288                            match (
12289                                language_scope.documentation_comment(),
12290                                language_scope.block_comment(),
12291                            ) {
12292                                (Some(config), _) | (_, Some(config))
12293                                    if buffer.contains_str_at(indent_end, &config.start) =>
12294                                {
12295                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12296                                }
12297                                (Some(config), _) | (_, Some(config))
12298                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12299                                {
12300                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12301                                }
12302                                (Some(config), _) | (_, Some(config))
12303                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12304                                {
12305                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12306                                }
12307                                (_, _) => language_scope
12308                                    .line_comment_prefixes()
12309                                    .iter()
12310                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12311                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12312                            }
12313                        } else {
12314                            // we not in an overridden comment node, but we may
12315                            // be within a non-overridden line comment node
12316                            language_scope
12317                                .line_comment_prefixes()
12318                                .iter()
12319                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12320                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12321                        };
12322
12323                        let rewrap_prefix = language_scope
12324                            .rewrap_prefixes()
12325                            .iter()
12326                            .find_map(|prefix_regex| {
12327                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12328                                    if mat.start() == 0 {
12329                                        Some(mat.as_str().to_string())
12330                                    } else {
12331                                        None
12332                                    }
12333                                })
12334                            })
12335                            .flatten();
12336                        (comment_delimiters, rewrap_prefix)
12337                    } else {
12338                        (None, None)
12339                    };
12340                    (indent, comment_prefix, rewrap_prefix)
12341                };
12342
12343            let mut ranges = Vec::new();
12344            let from_empty_selection = selection.is_empty();
12345
12346            let mut current_range_start = first_row;
12347            let mut prev_row = first_row;
12348            let (
12349                mut current_range_indent,
12350                mut current_range_comment_delimiters,
12351                mut current_range_rewrap_prefix,
12352            ) = indent_and_prefix_for_row(first_row);
12353
12354            for row in non_blank_rows_iter.skip(1) {
12355                let has_paragraph_break = row > prev_row + 1;
12356
12357                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12358                    indent_and_prefix_for_row(row);
12359
12360                let has_indent_change = row_indent != current_range_indent;
12361                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12362
12363                let has_boundary_change = has_comment_change
12364                    || row_rewrap_prefix.is_some()
12365                    || (has_indent_change && current_range_comment_delimiters.is_some());
12366
12367                if has_paragraph_break || has_boundary_change {
12368                    ranges.push((
12369                        language_settings.clone(),
12370                        Point::new(current_range_start, 0)
12371                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12372                        current_range_indent,
12373                        current_range_comment_delimiters.clone(),
12374                        current_range_rewrap_prefix.clone(),
12375                        from_empty_selection,
12376                    ));
12377                    current_range_start = row;
12378                    current_range_indent = row_indent;
12379                    current_range_comment_delimiters = row_comment_delimiters;
12380                    current_range_rewrap_prefix = row_rewrap_prefix;
12381                }
12382                prev_row = row;
12383            }
12384
12385            ranges.push((
12386                language_settings.clone(),
12387                Point::new(current_range_start, 0)
12388                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12389                current_range_indent,
12390                current_range_comment_delimiters,
12391                current_range_rewrap_prefix,
12392                from_empty_selection,
12393            ));
12394
12395            ranges
12396        });
12397
12398        let mut edits = Vec::new();
12399        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12400
12401        for (
12402            language_settings,
12403            wrap_range,
12404            mut indent_size,
12405            comment_prefix,
12406            rewrap_prefix,
12407            from_empty_selection,
12408        ) in wrap_ranges
12409        {
12410            let mut start_row = wrap_range.start.row;
12411            let mut end_row = wrap_range.end.row;
12412
12413            // Skip selections that overlap with a range that has already been rewrapped.
12414            let selection_range = start_row..end_row;
12415            if rewrapped_row_ranges
12416                .iter()
12417                .any(|range| range.overlaps(&selection_range))
12418            {
12419                continue;
12420            }
12421
12422            let tab_size = language_settings.tab_size;
12423
12424            let (line_prefix, inside_comment) = match &comment_prefix {
12425                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12426                    (Some(prefix.as_str()), true)
12427                }
12428                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12429                    (Some(prefix.as_ref()), true)
12430                }
12431                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12432                    start: _,
12433                    end: _,
12434                    prefix,
12435                    tab_size,
12436                })) => {
12437                    indent_size.len += tab_size;
12438                    (Some(prefix.as_ref()), true)
12439                }
12440                None => (None, false),
12441            };
12442            let indent_prefix = indent_size.chars().collect::<String>();
12443            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12444
12445            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12446                RewrapBehavior::InComments => inside_comment,
12447                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12448                RewrapBehavior::Anywhere => true,
12449            };
12450
12451            let should_rewrap = options.override_language_settings
12452                || allow_rewrap_based_on_language
12453                || self.hard_wrap.is_some();
12454            if !should_rewrap {
12455                continue;
12456            }
12457
12458            if from_empty_selection {
12459                'expand_upwards: while start_row > 0 {
12460                    let prev_row = start_row - 1;
12461                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12462                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12463                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12464                    {
12465                        start_row = prev_row;
12466                    } else {
12467                        break 'expand_upwards;
12468                    }
12469                }
12470
12471                'expand_downwards: while end_row < buffer.max_point().row {
12472                    let next_row = end_row + 1;
12473                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12474                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12475                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12476                    {
12477                        end_row = next_row;
12478                    } else {
12479                        break 'expand_downwards;
12480                    }
12481                }
12482            }
12483
12484            let start = Point::new(start_row, 0);
12485            let start_offset = ToOffset::to_offset(&start, &buffer);
12486            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12487            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12488            let mut first_line_delimiter = None;
12489            let mut last_line_delimiter = None;
12490            let Some(lines_without_prefixes) = selection_text
12491                .lines()
12492                .enumerate()
12493                .map(|(ix, line)| {
12494                    let line_trimmed = line.trim_start();
12495                    if rewrap_prefix.is_some() && ix > 0 {
12496                        Ok(line_trimmed)
12497                    } else if let Some(
12498                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12499                            start,
12500                            prefix,
12501                            end,
12502                            tab_size,
12503                        })
12504                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12505                            start,
12506                            prefix,
12507                            end,
12508                            tab_size,
12509                        }),
12510                    ) = &comment_prefix
12511                    {
12512                        let line_trimmed = line_trimmed
12513                            .strip_prefix(start.as_ref())
12514                            .map(|s| {
12515                                let mut indent_size = indent_size;
12516                                indent_size.len -= tab_size;
12517                                let indent_prefix: String = indent_size.chars().collect();
12518                                first_line_delimiter = Some((indent_prefix, start));
12519                                s.trim_start()
12520                            })
12521                            .unwrap_or(line_trimmed);
12522                        let line_trimmed = line_trimmed
12523                            .strip_suffix(end.as_ref())
12524                            .map(|s| {
12525                                last_line_delimiter = Some(end);
12526                                s.trim_end()
12527                            })
12528                            .unwrap_or(line_trimmed);
12529                        let line_trimmed = line_trimmed
12530                            .strip_prefix(prefix.as_ref())
12531                            .unwrap_or(line_trimmed);
12532                        Ok(line_trimmed)
12533                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12534                        line_trimmed.strip_prefix(prefix).with_context(|| {
12535                            format!("line did not start with prefix {prefix:?}: {line:?}")
12536                        })
12537                    } else {
12538                        line_trimmed
12539                            .strip_prefix(&line_prefix.trim_start())
12540                            .with_context(|| {
12541                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12542                            })
12543                    }
12544                })
12545                .collect::<Result<Vec<_>, _>>()
12546                .log_err()
12547            else {
12548                continue;
12549            };
12550
12551            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12552                buffer
12553                    .language_settings_at(Point::new(start_row, 0), cx)
12554                    .preferred_line_length as usize
12555            });
12556
12557            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12558                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12559            } else {
12560                line_prefix.clone()
12561            };
12562
12563            let wrapped_text = {
12564                let mut wrapped_text = wrap_with_prefix(
12565                    line_prefix,
12566                    subsequent_lines_prefix,
12567                    lines_without_prefixes.join("\n"),
12568                    wrap_column,
12569                    tab_size,
12570                    options.preserve_existing_whitespace,
12571                );
12572
12573                if let Some((indent, delimiter)) = first_line_delimiter {
12574                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12575                }
12576                if let Some(last_line) = last_line_delimiter {
12577                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12578                }
12579
12580                wrapped_text
12581            };
12582
12583            // TODO: should always use char-based diff while still supporting cursor behavior that
12584            // matches vim.
12585            let mut diff_options = DiffOptions::default();
12586            if options.override_language_settings {
12587                diff_options.max_word_diff_len = 0;
12588                diff_options.max_word_diff_line_count = 0;
12589            } else {
12590                diff_options.max_word_diff_len = usize::MAX;
12591                diff_options.max_word_diff_line_count = usize::MAX;
12592            }
12593
12594            for (old_range, new_text) in
12595                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12596            {
12597                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12598                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12599                edits.push((edit_start..edit_end, new_text));
12600            }
12601
12602            rewrapped_row_ranges.push(start_row..=end_row);
12603        }
12604
12605        self.buffer
12606            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12607    }
12608
12609    pub fn cut_common(
12610        &mut self,
12611        cut_no_selection_line: bool,
12612        window: &mut Window,
12613        cx: &mut Context<Self>,
12614    ) -> ClipboardItem {
12615        let mut text = String::new();
12616        let buffer = self.buffer.read(cx).snapshot(cx);
12617        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12618        let mut clipboard_selections = Vec::with_capacity(selections.len());
12619        {
12620            let max_point = buffer.max_point();
12621            let mut is_first = true;
12622            let mut prev_selection_was_entire_line = false;
12623            for selection in &mut selections {
12624                let is_entire_line =
12625                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12626                if is_entire_line {
12627                    selection.start = Point::new(selection.start.row, 0);
12628                    if !selection.is_empty() && selection.end.column == 0 {
12629                        selection.end = cmp::min(max_point, selection.end);
12630                    } else {
12631                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12632                    }
12633                    selection.goal = SelectionGoal::None;
12634                }
12635                if is_first {
12636                    is_first = false;
12637                } else if !prev_selection_was_entire_line {
12638                    text += "\n";
12639                }
12640                prev_selection_was_entire_line = is_entire_line;
12641                let mut len = 0;
12642                for chunk in buffer.text_for_range(selection.start..selection.end) {
12643                    text.push_str(chunk);
12644                    len += chunk.len();
12645                }
12646                clipboard_selections.push(ClipboardSelection {
12647                    len,
12648                    is_entire_line,
12649                    first_line_indent: buffer
12650                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12651                        .len,
12652                });
12653            }
12654        }
12655
12656        self.transact(window, cx, |this, window, cx| {
12657            this.change_selections(Default::default(), window, cx, |s| {
12658                s.select(selections);
12659            });
12660            this.insert("", window, cx);
12661        });
12662        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12663    }
12664
12665    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12666        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12667        let item = self.cut_common(true, window, cx);
12668        cx.write_to_clipboard(item);
12669    }
12670
12671    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12672        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12673        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12674            s.move_with(|snapshot, sel| {
12675                if sel.is_empty() {
12676                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12677                }
12678                if sel.is_empty() {
12679                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12680                }
12681            });
12682        });
12683        let item = self.cut_common(false, window, cx);
12684        cx.set_global(KillRing(item))
12685    }
12686
12687    pub fn kill_ring_yank(
12688        &mut self,
12689        _: &KillRingYank,
12690        window: &mut Window,
12691        cx: &mut Context<Self>,
12692    ) {
12693        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12694        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12695            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12696                (kill_ring.text().to_string(), kill_ring.metadata_json())
12697            } else {
12698                return;
12699            }
12700        } else {
12701            return;
12702        };
12703        self.do_paste(&text, metadata, false, window, cx);
12704    }
12705
12706    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12707        self.do_copy(true, cx);
12708    }
12709
12710    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12711        self.do_copy(false, cx);
12712    }
12713
12714    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12715        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12716        let buffer = self.buffer.read(cx).read(cx);
12717        let mut text = String::new();
12718
12719        let mut clipboard_selections = Vec::with_capacity(selections.len());
12720        {
12721            let max_point = buffer.max_point();
12722            let mut is_first = true;
12723            let mut prev_selection_was_entire_line = false;
12724            for selection in &selections {
12725                let mut start = selection.start;
12726                let mut end = selection.end;
12727                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12728                let mut add_trailing_newline = false;
12729                if is_entire_line {
12730                    start = Point::new(start.row, 0);
12731                    let next_line_start = Point::new(end.row + 1, 0);
12732                    if next_line_start <= max_point {
12733                        end = next_line_start;
12734                    } else {
12735                        // We're on the last line without a trailing newline.
12736                        // Copy to the end of the line and add a newline afterwards.
12737                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12738                        add_trailing_newline = true;
12739                    }
12740                }
12741
12742                let mut trimmed_selections = Vec::new();
12743                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12744                    let row = MultiBufferRow(start.row);
12745                    let first_indent = buffer.indent_size_for_line(row);
12746                    if first_indent.len == 0 || start.column > first_indent.len {
12747                        trimmed_selections.push(start..end);
12748                    } else {
12749                        trimmed_selections.push(
12750                            Point::new(row.0, first_indent.len)
12751                                ..Point::new(row.0, buffer.line_len(row)),
12752                        );
12753                        for row in start.row + 1..=end.row {
12754                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12755                            if row == end.row {
12756                                line_len = end.column;
12757                            }
12758                            if line_len == 0 {
12759                                trimmed_selections
12760                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12761                                continue;
12762                            }
12763                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12764                            if row_indent_size.len >= first_indent.len {
12765                                trimmed_selections.push(
12766                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12767                                );
12768                            } else {
12769                                trimmed_selections.clear();
12770                                trimmed_selections.push(start..end);
12771                                break;
12772                            }
12773                        }
12774                    }
12775                } else {
12776                    trimmed_selections.push(start..end);
12777                }
12778
12779                for trimmed_range in trimmed_selections {
12780                    if is_first {
12781                        is_first = false;
12782                    } else if !prev_selection_was_entire_line {
12783                        text += "\n";
12784                    }
12785                    prev_selection_was_entire_line = is_entire_line;
12786                    let mut len = 0;
12787                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12788                        text.push_str(chunk);
12789                        len += chunk.len();
12790                    }
12791                    if add_trailing_newline {
12792                        text.push('\n');
12793                        len += 1;
12794                    }
12795                    clipboard_selections.push(ClipboardSelection {
12796                        len,
12797                        is_entire_line,
12798                        first_line_indent: buffer
12799                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12800                            .len,
12801                    });
12802                }
12803            }
12804        }
12805
12806        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12807            text,
12808            clipboard_selections,
12809        ));
12810    }
12811
12812    pub fn do_paste(
12813        &mut self,
12814        text: &String,
12815        clipboard_selections: Option<Vec<ClipboardSelection>>,
12816        handle_entire_lines: bool,
12817        window: &mut Window,
12818        cx: &mut Context<Self>,
12819    ) {
12820        if self.read_only(cx) {
12821            return;
12822        }
12823
12824        let clipboard_text = Cow::Borrowed(text.as_str());
12825
12826        self.transact(window, cx, |this, window, cx| {
12827            let had_active_edit_prediction = this.has_active_edit_prediction();
12828            let display_map = this.display_snapshot(cx);
12829            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
12830            let cursor_offset = this
12831                .selections
12832                .last::<MultiBufferOffset>(&display_map)
12833                .head();
12834
12835            if let Some(mut clipboard_selections) = clipboard_selections {
12836                let all_selections_were_entire_line =
12837                    clipboard_selections.iter().all(|s| s.is_entire_line);
12838                let first_selection_indent_column =
12839                    clipboard_selections.first().map(|s| s.first_line_indent);
12840                if clipboard_selections.len() != old_selections.len() {
12841                    clipboard_selections.drain(..);
12842                }
12843                let mut auto_indent_on_paste = true;
12844
12845                this.buffer.update(cx, |buffer, cx| {
12846                    let snapshot = buffer.read(cx);
12847                    auto_indent_on_paste = snapshot
12848                        .language_settings_at(cursor_offset, cx)
12849                        .auto_indent_on_paste;
12850
12851                    let mut start_offset = 0;
12852                    let mut edits = Vec::new();
12853                    let mut original_indent_columns = Vec::new();
12854                    for (ix, selection) in old_selections.iter().enumerate() {
12855                        let to_insert;
12856                        let entire_line;
12857                        let original_indent_column;
12858                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12859                            let end_offset = start_offset + clipboard_selection.len;
12860                            to_insert = &clipboard_text[start_offset..end_offset];
12861                            entire_line = clipboard_selection.is_entire_line;
12862                            start_offset = if entire_line {
12863                                end_offset
12864                            } else {
12865                                end_offset + 1
12866                            };
12867                            original_indent_column = Some(clipboard_selection.first_line_indent);
12868                        } else {
12869                            to_insert = &*clipboard_text;
12870                            entire_line = all_selections_were_entire_line;
12871                            original_indent_column = first_selection_indent_column
12872                        }
12873
12874                        let (range, to_insert) =
12875                            if selection.is_empty() && handle_entire_lines && entire_line {
12876                                // If the corresponding selection was empty when this slice of the
12877                                // clipboard text was written, then the entire line containing the
12878                                // selection was copied. If this selection is also currently empty,
12879                                // then paste the line before the current line of the buffer.
12880                                let column = selection.start.to_point(&snapshot).column as usize;
12881                                let line_start = selection.start - column;
12882                                (line_start..line_start, Cow::Borrowed(to_insert))
12883                            } else {
12884                                let language = snapshot.language_at(selection.head());
12885                                let range = selection.range();
12886                                if let Some(language) = language
12887                                    && language.name() == "Markdown".into()
12888                                {
12889                                    edit_for_markdown_paste(
12890                                        &snapshot,
12891                                        range,
12892                                        to_insert,
12893                                        url::Url::parse(to_insert).ok(),
12894                                    )
12895                                } else {
12896                                    (range, Cow::Borrowed(to_insert))
12897                                }
12898                            };
12899
12900                        edits.push((range, to_insert));
12901                        original_indent_columns.push(original_indent_column);
12902                    }
12903                    drop(snapshot);
12904
12905                    buffer.edit(
12906                        edits,
12907                        if auto_indent_on_paste {
12908                            Some(AutoindentMode::Block {
12909                                original_indent_columns,
12910                            })
12911                        } else {
12912                            None
12913                        },
12914                        cx,
12915                    );
12916                });
12917
12918                let selections = this
12919                    .selections
12920                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12921                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12922            } else {
12923                let url = url::Url::parse(&clipboard_text).ok();
12924
12925                let auto_indent_mode = if !clipboard_text.is_empty() {
12926                    Some(AutoindentMode::Block {
12927                        original_indent_columns: Vec::new(),
12928                    })
12929                } else {
12930                    None
12931                };
12932
12933                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12934                    let snapshot = buffer.snapshot(cx);
12935
12936                    let anchors = old_selections
12937                        .iter()
12938                        .map(|s| {
12939                            let anchor = snapshot.anchor_after(s.head());
12940                            s.map(|_| anchor)
12941                        })
12942                        .collect::<Vec<_>>();
12943
12944                    let mut edits = Vec::new();
12945
12946                    for selection in old_selections.iter() {
12947                        let language = snapshot.language_at(selection.head());
12948                        let range = selection.range();
12949
12950                        let (edit_range, edit_text) = if let Some(language) = language
12951                            && language.name() == "Markdown".into()
12952                        {
12953                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12954                        } else {
12955                            (range, clipboard_text.clone())
12956                        };
12957
12958                        edits.push((edit_range, edit_text));
12959                    }
12960
12961                    drop(snapshot);
12962                    buffer.edit(edits, auto_indent_mode, cx);
12963
12964                    anchors
12965                });
12966
12967                this.change_selections(Default::default(), window, cx, |s| {
12968                    s.select_anchors(selection_anchors);
12969                });
12970            }
12971
12972            //   🤔                 |    ..     | show_in_menu |
12973            // | ..                  |   true        true
12974            // | had_edit_prediction |   false       true
12975
12976            let trigger_in_words =
12977                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12978
12979            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12980        });
12981    }
12982
12983    pub fn diff_clipboard_with_selection(
12984        &mut self,
12985        _: &DiffClipboardWithSelection,
12986        window: &mut Window,
12987        cx: &mut Context<Self>,
12988    ) {
12989        let selections = self
12990            .selections
12991            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
12992
12993        if selections.is_empty() {
12994            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12995            return;
12996        };
12997
12998        let clipboard_text = match cx.read_from_clipboard() {
12999            Some(item) => match item.entries().first() {
13000                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13001                _ => None,
13002            },
13003            None => None,
13004        };
13005
13006        let Some(clipboard_text) = clipboard_text else {
13007            log::warn!("Clipboard doesn't contain text.");
13008            return;
13009        };
13010
13011        window.dispatch_action(
13012            Box::new(DiffClipboardWithSelectionData {
13013                clipboard_text,
13014                editor: cx.entity(),
13015            }),
13016            cx,
13017        );
13018    }
13019
13020    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13021        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13022        if let Some(item) = cx.read_from_clipboard() {
13023            let entries = item.entries();
13024
13025            match entries.first() {
13026                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13027                // of all the pasted entries.
13028                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13029                    .do_paste(
13030                        clipboard_string.text(),
13031                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13032                        true,
13033                        window,
13034                        cx,
13035                    ),
13036                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13037            }
13038        }
13039    }
13040
13041    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13042        if self.read_only(cx) {
13043            return;
13044        }
13045
13046        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13047
13048        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13049            if let Some((selections, _)) =
13050                self.selection_history.transaction(transaction_id).cloned()
13051            {
13052                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13053                    s.select_anchors(selections.to_vec());
13054                });
13055            } else {
13056                log::error!(
13057                    "No entry in selection_history found for undo. \
13058                     This may correspond to a bug where undo does not update the selection. \
13059                     If this is occurring, please add details to \
13060                     https://github.com/zed-industries/zed/issues/22692"
13061                );
13062            }
13063            self.request_autoscroll(Autoscroll::fit(), cx);
13064            self.unmark_text(window, cx);
13065            self.refresh_edit_prediction(true, false, window, cx);
13066            cx.emit(EditorEvent::Edited { transaction_id });
13067            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13068        }
13069    }
13070
13071    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13072        if self.read_only(cx) {
13073            return;
13074        }
13075
13076        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13077
13078        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13079            if let Some((_, Some(selections))) =
13080                self.selection_history.transaction(transaction_id).cloned()
13081            {
13082                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13083                    s.select_anchors(selections.to_vec());
13084                });
13085            } else {
13086                log::error!(
13087                    "No entry in selection_history found for redo. \
13088                     This may correspond to a bug where undo does not update the selection. \
13089                     If this is occurring, please add details to \
13090                     https://github.com/zed-industries/zed/issues/22692"
13091                );
13092            }
13093            self.request_autoscroll(Autoscroll::fit(), cx);
13094            self.unmark_text(window, cx);
13095            self.refresh_edit_prediction(true, false, window, cx);
13096            cx.emit(EditorEvent::Edited { transaction_id });
13097        }
13098    }
13099
13100    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13101        self.buffer
13102            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13103    }
13104
13105    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13106        self.buffer
13107            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13108    }
13109
13110    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13112        self.change_selections(Default::default(), window, cx, |s| {
13113            s.move_with(|map, selection| {
13114                let cursor = if selection.is_empty() {
13115                    movement::left(map, selection.start)
13116                } else {
13117                    selection.start
13118                };
13119                selection.collapse_to(cursor, SelectionGoal::None);
13120            });
13121        })
13122    }
13123
13124    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13125        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13126        self.change_selections(Default::default(), window, cx, |s| {
13127            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13128        })
13129    }
13130
13131    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13132        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13133        self.change_selections(Default::default(), window, cx, |s| {
13134            s.move_with(|map, selection| {
13135                let cursor = if selection.is_empty() {
13136                    movement::right(map, selection.end)
13137                } else {
13138                    selection.end
13139                };
13140                selection.collapse_to(cursor, SelectionGoal::None)
13141            });
13142        })
13143    }
13144
13145    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13146        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13147        self.change_selections(Default::default(), window, cx, |s| {
13148            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13149        });
13150    }
13151
13152    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13153        if self.take_rename(true, window, cx).is_some() {
13154            return;
13155        }
13156
13157        if self.mode.is_single_line() {
13158            cx.propagate();
13159            return;
13160        }
13161
13162        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13163
13164        let text_layout_details = &self.text_layout_details(window);
13165        let selection_count = self.selections.count();
13166        let first_selection = self.selections.first_anchor();
13167
13168        self.change_selections(Default::default(), window, cx, |s| {
13169            s.move_with(|map, selection| {
13170                if !selection.is_empty() {
13171                    selection.goal = SelectionGoal::None;
13172                }
13173                let (cursor, goal) = movement::up(
13174                    map,
13175                    selection.start,
13176                    selection.goal,
13177                    false,
13178                    text_layout_details,
13179                );
13180                selection.collapse_to(cursor, goal);
13181            });
13182        });
13183
13184        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13185        {
13186            cx.propagate();
13187        }
13188    }
13189
13190    pub fn move_up_by_lines(
13191        &mut self,
13192        action: &MoveUpByLines,
13193        window: &mut Window,
13194        cx: &mut Context<Self>,
13195    ) {
13196        if self.take_rename(true, window, cx).is_some() {
13197            return;
13198        }
13199
13200        if self.mode.is_single_line() {
13201            cx.propagate();
13202            return;
13203        }
13204
13205        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13206
13207        let text_layout_details = &self.text_layout_details(window);
13208
13209        self.change_selections(Default::default(), window, cx, |s| {
13210            s.move_with(|map, selection| {
13211                if !selection.is_empty() {
13212                    selection.goal = SelectionGoal::None;
13213                }
13214                let (cursor, goal) = movement::up_by_rows(
13215                    map,
13216                    selection.start,
13217                    action.lines,
13218                    selection.goal,
13219                    false,
13220                    text_layout_details,
13221                );
13222                selection.collapse_to(cursor, goal);
13223            });
13224        })
13225    }
13226
13227    pub fn move_down_by_lines(
13228        &mut self,
13229        action: &MoveDownByLines,
13230        window: &mut Window,
13231        cx: &mut Context<Self>,
13232    ) {
13233        if self.take_rename(true, window, cx).is_some() {
13234            return;
13235        }
13236
13237        if self.mode.is_single_line() {
13238            cx.propagate();
13239            return;
13240        }
13241
13242        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13243
13244        let text_layout_details = &self.text_layout_details(window);
13245
13246        self.change_selections(Default::default(), window, cx, |s| {
13247            s.move_with(|map, selection| {
13248                if !selection.is_empty() {
13249                    selection.goal = SelectionGoal::None;
13250                }
13251                let (cursor, goal) = movement::down_by_rows(
13252                    map,
13253                    selection.start,
13254                    action.lines,
13255                    selection.goal,
13256                    false,
13257                    text_layout_details,
13258                );
13259                selection.collapse_to(cursor, goal);
13260            });
13261        })
13262    }
13263
13264    pub fn select_down_by_lines(
13265        &mut self,
13266        action: &SelectDownByLines,
13267        window: &mut Window,
13268        cx: &mut Context<Self>,
13269    ) {
13270        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13271        let text_layout_details = &self.text_layout_details(window);
13272        self.change_selections(Default::default(), window, cx, |s| {
13273            s.move_heads_with(|map, head, goal| {
13274                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13275            })
13276        })
13277    }
13278
13279    pub fn select_up_by_lines(
13280        &mut self,
13281        action: &SelectUpByLines,
13282        window: &mut Window,
13283        cx: &mut Context<Self>,
13284    ) {
13285        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13286        let text_layout_details = &self.text_layout_details(window);
13287        self.change_selections(Default::default(), window, cx, |s| {
13288            s.move_heads_with(|map, head, goal| {
13289                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13290            })
13291        })
13292    }
13293
13294    pub fn select_page_up(
13295        &mut self,
13296        _: &SelectPageUp,
13297        window: &mut Window,
13298        cx: &mut Context<Self>,
13299    ) {
13300        let Some(row_count) = self.visible_row_count() else {
13301            return;
13302        };
13303
13304        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13305
13306        let text_layout_details = &self.text_layout_details(window);
13307
13308        self.change_selections(Default::default(), window, cx, |s| {
13309            s.move_heads_with(|map, head, goal| {
13310                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13311            })
13312        })
13313    }
13314
13315    pub fn move_page_up(
13316        &mut self,
13317        action: &MovePageUp,
13318        window: &mut Window,
13319        cx: &mut Context<Self>,
13320    ) {
13321        if self.take_rename(true, window, cx).is_some() {
13322            return;
13323        }
13324
13325        if self
13326            .context_menu
13327            .borrow_mut()
13328            .as_mut()
13329            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13330            .unwrap_or(false)
13331        {
13332            return;
13333        }
13334
13335        if matches!(self.mode, EditorMode::SingleLine) {
13336            cx.propagate();
13337            return;
13338        }
13339
13340        let Some(row_count) = self.visible_row_count() else {
13341            return;
13342        };
13343
13344        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13345
13346        let effects = if action.center_cursor {
13347            SelectionEffects::scroll(Autoscroll::center())
13348        } else {
13349            SelectionEffects::default()
13350        };
13351
13352        let text_layout_details = &self.text_layout_details(window);
13353
13354        self.change_selections(effects, window, cx, |s| {
13355            s.move_with(|map, selection| {
13356                if !selection.is_empty() {
13357                    selection.goal = SelectionGoal::None;
13358                }
13359                let (cursor, goal) = movement::up_by_rows(
13360                    map,
13361                    selection.end,
13362                    row_count,
13363                    selection.goal,
13364                    false,
13365                    text_layout_details,
13366                );
13367                selection.collapse_to(cursor, goal);
13368            });
13369        });
13370    }
13371
13372    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13373        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13374        let text_layout_details = &self.text_layout_details(window);
13375        self.change_selections(Default::default(), window, cx, |s| {
13376            s.move_heads_with(|map, head, goal| {
13377                movement::up(map, head, goal, false, text_layout_details)
13378            })
13379        })
13380    }
13381
13382    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13383        self.take_rename(true, window, cx);
13384
13385        if self.mode.is_single_line() {
13386            cx.propagate();
13387            return;
13388        }
13389
13390        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13391
13392        let text_layout_details = &self.text_layout_details(window);
13393        let selection_count = self.selections.count();
13394        let first_selection = self.selections.first_anchor();
13395
13396        self.change_selections(Default::default(), window, cx, |s| {
13397            s.move_with(|map, selection| {
13398                if !selection.is_empty() {
13399                    selection.goal = SelectionGoal::None;
13400                }
13401                let (cursor, goal) = movement::down(
13402                    map,
13403                    selection.end,
13404                    selection.goal,
13405                    false,
13406                    text_layout_details,
13407                );
13408                selection.collapse_to(cursor, goal);
13409            });
13410        });
13411
13412        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13413        {
13414            cx.propagate();
13415        }
13416    }
13417
13418    pub fn select_page_down(
13419        &mut self,
13420        _: &SelectPageDown,
13421        window: &mut Window,
13422        cx: &mut Context<Self>,
13423    ) {
13424        let Some(row_count) = self.visible_row_count() else {
13425            return;
13426        };
13427
13428        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13429
13430        let text_layout_details = &self.text_layout_details(window);
13431
13432        self.change_selections(Default::default(), window, cx, |s| {
13433            s.move_heads_with(|map, head, goal| {
13434                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13435            })
13436        })
13437    }
13438
13439    pub fn move_page_down(
13440        &mut self,
13441        action: &MovePageDown,
13442        window: &mut Window,
13443        cx: &mut Context<Self>,
13444    ) {
13445        if self.take_rename(true, window, cx).is_some() {
13446            return;
13447        }
13448
13449        if self
13450            .context_menu
13451            .borrow_mut()
13452            .as_mut()
13453            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13454            .unwrap_or(false)
13455        {
13456            return;
13457        }
13458
13459        if matches!(self.mode, EditorMode::SingleLine) {
13460            cx.propagate();
13461            return;
13462        }
13463
13464        let Some(row_count) = self.visible_row_count() else {
13465            return;
13466        };
13467
13468        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13469
13470        let effects = if action.center_cursor {
13471            SelectionEffects::scroll(Autoscroll::center())
13472        } else {
13473            SelectionEffects::default()
13474        };
13475
13476        let text_layout_details = &self.text_layout_details(window);
13477        self.change_selections(effects, window, cx, |s| {
13478            s.move_with(|map, selection| {
13479                if !selection.is_empty() {
13480                    selection.goal = SelectionGoal::None;
13481                }
13482                let (cursor, goal) = movement::down_by_rows(
13483                    map,
13484                    selection.end,
13485                    row_count,
13486                    selection.goal,
13487                    false,
13488                    text_layout_details,
13489                );
13490                selection.collapse_to(cursor, goal);
13491            });
13492        });
13493    }
13494
13495    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13496        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13497        let text_layout_details = &self.text_layout_details(window);
13498        self.change_selections(Default::default(), window, cx, |s| {
13499            s.move_heads_with(|map, head, goal| {
13500                movement::down(map, head, goal, false, text_layout_details)
13501            })
13502        });
13503    }
13504
13505    pub fn context_menu_first(
13506        &mut self,
13507        _: &ContextMenuFirst,
13508        window: &mut Window,
13509        cx: &mut Context<Self>,
13510    ) {
13511        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13512            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13513        }
13514    }
13515
13516    pub fn context_menu_prev(
13517        &mut self,
13518        _: &ContextMenuPrevious,
13519        window: &mut Window,
13520        cx: &mut Context<Self>,
13521    ) {
13522        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13523            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13524        }
13525    }
13526
13527    pub fn context_menu_next(
13528        &mut self,
13529        _: &ContextMenuNext,
13530        window: &mut Window,
13531        cx: &mut Context<Self>,
13532    ) {
13533        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13534            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13535        }
13536    }
13537
13538    pub fn context_menu_last(
13539        &mut self,
13540        _: &ContextMenuLast,
13541        window: &mut Window,
13542        cx: &mut Context<Self>,
13543    ) {
13544        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13545            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13546        }
13547    }
13548
13549    pub fn signature_help_prev(
13550        &mut self,
13551        _: &SignatureHelpPrevious,
13552        _: &mut Window,
13553        cx: &mut Context<Self>,
13554    ) {
13555        if let Some(popover) = self.signature_help_state.popover_mut() {
13556            if popover.current_signature == 0 {
13557                popover.current_signature = popover.signatures.len() - 1;
13558            } else {
13559                popover.current_signature -= 1;
13560            }
13561            cx.notify();
13562        }
13563    }
13564
13565    pub fn signature_help_next(
13566        &mut self,
13567        _: &SignatureHelpNext,
13568        _: &mut Window,
13569        cx: &mut Context<Self>,
13570    ) {
13571        if let Some(popover) = self.signature_help_state.popover_mut() {
13572            if popover.current_signature + 1 == popover.signatures.len() {
13573                popover.current_signature = 0;
13574            } else {
13575                popover.current_signature += 1;
13576            }
13577            cx.notify();
13578        }
13579    }
13580
13581    pub fn move_to_previous_word_start(
13582        &mut self,
13583        _: &MoveToPreviousWordStart,
13584        window: &mut Window,
13585        cx: &mut Context<Self>,
13586    ) {
13587        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13588        self.change_selections(Default::default(), window, cx, |s| {
13589            s.move_cursors_with(|map, head, _| {
13590                (
13591                    movement::previous_word_start(map, head),
13592                    SelectionGoal::None,
13593                )
13594            });
13595        })
13596    }
13597
13598    pub fn move_to_previous_subword_start(
13599        &mut self,
13600        _: &MoveToPreviousSubwordStart,
13601        window: &mut Window,
13602        cx: &mut Context<Self>,
13603    ) {
13604        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13605        self.change_selections(Default::default(), window, cx, |s| {
13606            s.move_cursors_with(|map, head, _| {
13607                (
13608                    movement::previous_subword_start(map, head),
13609                    SelectionGoal::None,
13610                )
13611            });
13612        })
13613    }
13614
13615    pub fn select_to_previous_word_start(
13616        &mut self,
13617        _: &SelectToPreviousWordStart,
13618        window: &mut Window,
13619        cx: &mut Context<Self>,
13620    ) {
13621        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13622        self.change_selections(Default::default(), window, cx, |s| {
13623            s.move_heads_with(|map, head, _| {
13624                (
13625                    movement::previous_word_start(map, head),
13626                    SelectionGoal::None,
13627                )
13628            });
13629        })
13630    }
13631
13632    pub fn select_to_previous_subword_start(
13633        &mut self,
13634        _: &SelectToPreviousSubwordStart,
13635        window: &mut Window,
13636        cx: &mut Context<Self>,
13637    ) {
13638        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13639        self.change_selections(Default::default(), window, cx, |s| {
13640            s.move_heads_with(|map, head, _| {
13641                (
13642                    movement::previous_subword_start(map, head),
13643                    SelectionGoal::None,
13644                )
13645            });
13646        })
13647    }
13648
13649    pub fn delete_to_previous_word_start(
13650        &mut self,
13651        action: &DeleteToPreviousWordStart,
13652        window: &mut Window,
13653        cx: &mut Context<Self>,
13654    ) {
13655        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13656        self.transact(window, cx, |this, window, cx| {
13657            this.select_autoclose_pair(window, cx);
13658            this.change_selections(Default::default(), window, cx, |s| {
13659                s.move_with(|map, selection| {
13660                    if selection.is_empty() {
13661                        let mut cursor = if action.ignore_newlines {
13662                            movement::previous_word_start(map, selection.head())
13663                        } else {
13664                            movement::previous_word_start_or_newline(map, selection.head())
13665                        };
13666                        cursor = movement::adjust_greedy_deletion(
13667                            map,
13668                            selection.head(),
13669                            cursor,
13670                            action.ignore_brackets,
13671                        );
13672                        selection.set_head(cursor, SelectionGoal::None);
13673                    }
13674                });
13675            });
13676            this.insert("", window, cx);
13677        });
13678    }
13679
13680    pub fn delete_to_previous_subword_start(
13681        &mut self,
13682        _: &DeleteToPreviousSubwordStart,
13683        window: &mut Window,
13684        cx: &mut Context<Self>,
13685    ) {
13686        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13687        self.transact(window, cx, |this, window, cx| {
13688            this.select_autoclose_pair(window, cx);
13689            this.change_selections(Default::default(), window, cx, |s| {
13690                s.move_with(|map, selection| {
13691                    if selection.is_empty() {
13692                        let mut cursor = movement::previous_subword_start(map, selection.head());
13693                        cursor =
13694                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13695                        selection.set_head(cursor, SelectionGoal::None);
13696                    }
13697                });
13698            });
13699            this.insert("", window, cx);
13700        });
13701    }
13702
13703    pub fn move_to_next_word_end(
13704        &mut self,
13705        _: &MoveToNextWordEnd,
13706        window: &mut Window,
13707        cx: &mut Context<Self>,
13708    ) {
13709        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13710        self.change_selections(Default::default(), window, cx, |s| {
13711            s.move_cursors_with(|map, head, _| {
13712                (movement::next_word_end(map, head), SelectionGoal::None)
13713            });
13714        })
13715    }
13716
13717    pub fn move_to_next_subword_end(
13718        &mut self,
13719        _: &MoveToNextSubwordEnd,
13720        window: &mut Window,
13721        cx: &mut Context<Self>,
13722    ) {
13723        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13724        self.change_selections(Default::default(), window, cx, |s| {
13725            s.move_cursors_with(|map, head, _| {
13726                (movement::next_subword_end(map, head), SelectionGoal::None)
13727            });
13728        })
13729    }
13730
13731    pub fn select_to_next_word_end(
13732        &mut self,
13733        _: &SelectToNextWordEnd,
13734        window: &mut Window,
13735        cx: &mut Context<Self>,
13736    ) {
13737        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13738        self.change_selections(Default::default(), window, cx, |s| {
13739            s.move_heads_with(|map, head, _| {
13740                (movement::next_word_end(map, head), SelectionGoal::None)
13741            });
13742        })
13743    }
13744
13745    pub fn select_to_next_subword_end(
13746        &mut self,
13747        _: &SelectToNextSubwordEnd,
13748        window: &mut Window,
13749        cx: &mut Context<Self>,
13750    ) {
13751        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13752        self.change_selections(Default::default(), window, cx, |s| {
13753            s.move_heads_with(|map, head, _| {
13754                (movement::next_subword_end(map, head), SelectionGoal::None)
13755            });
13756        })
13757    }
13758
13759    pub fn delete_to_next_word_end(
13760        &mut self,
13761        action: &DeleteToNextWordEnd,
13762        window: &mut Window,
13763        cx: &mut Context<Self>,
13764    ) {
13765        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13766        self.transact(window, cx, |this, window, cx| {
13767            this.change_selections(Default::default(), window, cx, |s| {
13768                s.move_with(|map, selection| {
13769                    if selection.is_empty() {
13770                        let mut cursor = if action.ignore_newlines {
13771                            movement::next_word_end(map, selection.head())
13772                        } else {
13773                            movement::next_word_end_or_newline(map, selection.head())
13774                        };
13775                        cursor = movement::adjust_greedy_deletion(
13776                            map,
13777                            selection.head(),
13778                            cursor,
13779                            action.ignore_brackets,
13780                        );
13781                        selection.set_head(cursor, SelectionGoal::None);
13782                    }
13783                });
13784            });
13785            this.insert("", window, cx);
13786        });
13787    }
13788
13789    pub fn delete_to_next_subword_end(
13790        &mut self,
13791        _: &DeleteToNextSubwordEnd,
13792        window: &mut Window,
13793        cx: &mut Context<Self>,
13794    ) {
13795        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13796        self.transact(window, cx, |this, window, cx| {
13797            this.change_selections(Default::default(), window, cx, |s| {
13798                s.move_with(|map, selection| {
13799                    if selection.is_empty() {
13800                        let mut cursor = movement::next_subword_end(map, selection.head());
13801                        cursor =
13802                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13803                        selection.set_head(cursor, SelectionGoal::None);
13804                    }
13805                });
13806            });
13807            this.insert("", window, cx);
13808        });
13809    }
13810
13811    pub fn move_to_beginning_of_line(
13812        &mut self,
13813        action: &MoveToBeginningOfLine,
13814        window: &mut Window,
13815        cx: &mut Context<Self>,
13816    ) {
13817        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13818        self.change_selections(Default::default(), window, cx, |s| {
13819            s.move_cursors_with(|map, head, _| {
13820                (
13821                    movement::indented_line_beginning(
13822                        map,
13823                        head,
13824                        action.stop_at_soft_wraps,
13825                        action.stop_at_indent,
13826                    ),
13827                    SelectionGoal::None,
13828                )
13829            });
13830        })
13831    }
13832
13833    pub fn select_to_beginning_of_line(
13834        &mut self,
13835        action: &SelectToBeginningOfLine,
13836        window: &mut Window,
13837        cx: &mut Context<Self>,
13838    ) {
13839        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13840        self.change_selections(Default::default(), window, cx, |s| {
13841            s.move_heads_with(|map, head, _| {
13842                (
13843                    movement::indented_line_beginning(
13844                        map,
13845                        head,
13846                        action.stop_at_soft_wraps,
13847                        action.stop_at_indent,
13848                    ),
13849                    SelectionGoal::None,
13850                )
13851            });
13852        });
13853    }
13854
13855    pub fn delete_to_beginning_of_line(
13856        &mut self,
13857        action: &DeleteToBeginningOfLine,
13858        window: &mut Window,
13859        cx: &mut Context<Self>,
13860    ) {
13861        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13862        self.transact(window, cx, |this, window, cx| {
13863            this.change_selections(Default::default(), window, cx, |s| {
13864                s.move_with(|_, selection| {
13865                    selection.reversed = true;
13866                });
13867            });
13868
13869            this.select_to_beginning_of_line(
13870                &SelectToBeginningOfLine {
13871                    stop_at_soft_wraps: false,
13872                    stop_at_indent: action.stop_at_indent,
13873                },
13874                window,
13875                cx,
13876            );
13877            this.backspace(&Backspace, window, cx);
13878        });
13879    }
13880
13881    pub fn move_to_end_of_line(
13882        &mut self,
13883        action: &MoveToEndOfLine,
13884        window: &mut Window,
13885        cx: &mut Context<Self>,
13886    ) {
13887        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13888        self.change_selections(Default::default(), window, cx, |s| {
13889            s.move_cursors_with(|map, head, _| {
13890                (
13891                    movement::line_end(map, head, action.stop_at_soft_wraps),
13892                    SelectionGoal::None,
13893                )
13894            });
13895        })
13896    }
13897
13898    pub fn select_to_end_of_line(
13899        &mut self,
13900        action: &SelectToEndOfLine,
13901        window: &mut Window,
13902        cx: &mut Context<Self>,
13903    ) {
13904        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13905        self.change_selections(Default::default(), window, cx, |s| {
13906            s.move_heads_with(|map, head, _| {
13907                (
13908                    movement::line_end(map, head, action.stop_at_soft_wraps),
13909                    SelectionGoal::None,
13910                )
13911            });
13912        })
13913    }
13914
13915    pub fn delete_to_end_of_line(
13916        &mut self,
13917        _: &DeleteToEndOfLine,
13918        window: &mut Window,
13919        cx: &mut Context<Self>,
13920    ) {
13921        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13922        self.transact(window, cx, |this, window, cx| {
13923            this.select_to_end_of_line(
13924                &SelectToEndOfLine {
13925                    stop_at_soft_wraps: false,
13926                },
13927                window,
13928                cx,
13929            );
13930            this.delete(&Delete, window, cx);
13931        });
13932    }
13933
13934    pub fn cut_to_end_of_line(
13935        &mut self,
13936        action: &CutToEndOfLine,
13937        window: &mut Window,
13938        cx: &mut Context<Self>,
13939    ) {
13940        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13941        self.transact(window, cx, |this, window, cx| {
13942            this.select_to_end_of_line(
13943                &SelectToEndOfLine {
13944                    stop_at_soft_wraps: false,
13945                },
13946                window,
13947                cx,
13948            );
13949            if !action.stop_at_newlines {
13950                this.change_selections(Default::default(), window, cx, |s| {
13951                    s.move_with(|_, sel| {
13952                        if sel.is_empty() {
13953                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13954                        }
13955                    });
13956                });
13957            }
13958            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13959            let item = this.cut_common(false, window, cx);
13960            cx.write_to_clipboard(item);
13961        });
13962    }
13963
13964    pub fn move_to_start_of_paragraph(
13965        &mut self,
13966        _: &MoveToStartOfParagraph,
13967        window: &mut Window,
13968        cx: &mut Context<Self>,
13969    ) {
13970        if matches!(self.mode, EditorMode::SingleLine) {
13971            cx.propagate();
13972            return;
13973        }
13974        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13975        self.change_selections(Default::default(), window, cx, |s| {
13976            s.move_with(|map, selection| {
13977                selection.collapse_to(
13978                    movement::start_of_paragraph(map, selection.head(), 1),
13979                    SelectionGoal::None,
13980                )
13981            });
13982        })
13983    }
13984
13985    pub fn move_to_end_of_paragraph(
13986        &mut self,
13987        _: &MoveToEndOfParagraph,
13988        window: &mut Window,
13989        cx: &mut Context<Self>,
13990    ) {
13991        if matches!(self.mode, EditorMode::SingleLine) {
13992            cx.propagate();
13993            return;
13994        }
13995        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13996        self.change_selections(Default::default(), window, cx, |s| {
13997            s.move_with(|map, selection| {
13998                selection.collapse_to(
13999                    movement::end_of_paragraph(map, selection.head(), 1),
14000                    SelectionGoal::None,
14001                )
14002            });
14003        })
14004    }
14005
14006    pub fn select_to_start_of_paragraph(
14007        &mut self,
14008        _: &SelectToStartOfParagraph,
14009        window: &mut Window,
14010        cx: &mut Context<Self>,
14011    ) {
14012        if matches!(self.mode, EditorMode::SingleLine) {
14013            cx.propagate();
14014            return;
14015        }
14016        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14017        self.change_selections(Default::default(), window, cx, |s| {
14018            s.move_heads_with(|map, head, _| {
14019                (
14020                    movement::start_of_paragraph(map, head, 1),
14021                    SelectionGoal::None,
14022                )
14023            });
14024        })
14025    }
14026
14027    pub fn select_to_end_of_paragraph(
14028        &mut self,
14029        _: &SelectToEndOfParagraph,
14030        window: &mut Window,
14031        cx: &mut Context<Self>,
14032    ) {
14033        if matches!(self.mode, EditorMode::SingleLine) {
14034            cx.propagate();
14035            return;
14036        }
14037        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14038        self.change_selections(Default::default(), window, cx, |s| {
14039            s.move_heads_with(|map, head, _| {
14040                (
14041                    movement::end_of_paragraph(map, head, 1),
14042                    SelectionGoal::None,
14043                )
14044            });
14045        })
14046    }
14047
14048    pub fn move_to_start_of_excerpt(
14049        &mut self,
14050        _: &MoveToStartOfExcerpt,
14051        window: &mut Window,
14052        cx: &mut Context<Self>,
14053    ) {
14054        if matches!(self.mode, EditorMode::SingleLine) {
14055            cx.propagate();
14056            return;
14057        }
14058        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14059        self.change_selections(Default::default(), window, cx, |s| {
14060            s.move_with(|map, selection| {
14061                selection.collapse_to(
14062                    movement::start_of_excerpt(
14063                        map,
14064                        selection.head(),
14065                        workspace::searchable::Direction::Prev,
14066                    ),
14067                    SelectionGoal::None,
14068                )
14069            });
14070        })
14071    }
14072
14073    pub fn move_to_start_of_next_excerpt(
14074        &mut self,
14075        _: &MoveToStartOfNextExcerpt,
14076        window: &mut Window,
14077        cx: &mut Context<Self>,
14078    ) {
14079        if matches!(self.mode, EditorMode::SingleLine) {
14080            cx.propagate();
14081            return;
14082        }
14083
14084        self.change_selections(Default::default(), window, cx, |s| {
14085            s.move_with(|map, selection| {
14086                selection.collapse_to(
14087                    movement::start_of_excerpt(
14088                        map,
14089                        selection.head(),
14090                        workspace::searchable::Direction::Next,
14091                    ),
14092                    SelectionGoal::None,
14093                )
14094            });
14095        })
14096    }
14097
14098    pub fn move_to_end_of_excerpt(
14099        &mut self,
14100        _: &MoveToEndOfExcerpt,
14101        window: &mut Window,
14102        cx: &mut Context<Self>,
14103    ) {
14104        if matches!(self.mode, EditorMode::SingleLine) {
14105            cx.propagate();
14106            return;
14107        }
14108        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14109        self.change_selections(Default::default(), window, cx, |s| {
14110            s.move_with(|map, selection| {
14111                selection.collapse_to(
14112                    movement::end_of_excerpt(
14113                        map,
14114                        selection.head(),
14115                        workspace::searchable::Direction::Next,
14116                    ),
14117                    SelectionGoal::None,
14118                )
14119            });
14120        })
14121    }
14122
14123    pub fn move_to_end_of_previous_excerpt(
14124        &mut self,
14125        _: &MoveToEndOfPreviousExcerpt,
14126        window: &mut Window,
14127        cx: &mut Context<Self>,
14128    ) {
14129        if matches!(self.mode, EditorMode::SingleLine) {
14130            cx.propagate();
14131            return;
14132        }
14133        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14134        self.change_selections(Default::default(), window, cx, |s| {
14135            s.move_with(|map, selection| {
14136                selection.collapse_to(
14137                    movement::end_of_excerpt(
14138                        map,
14139                        selection.head(),
14140                        workspace::searchable::Direction::Prev,
14141                    ),
14142                    SelectionGoal::None,
14143                )
14144            });
14145        })
14146    }
14147
14148    pub fn select_to_start_of_excerpt(
14149        &mut self,
14150        _: &SelectToStartOfExcerpt,
14151        window: &mut Window,
14152        cx: &mut Context<Self>,
14153    ) {
14154        if matches!(self.mode, EditorMode::SingleLine) {
14155            cx.propagate();
14156            return;
14157        }
14158        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14159        self.change_selections(Default::default(), window, cx, |s| {
14160            s.move_heads_with(|map, head, _| {
14161                (
14162                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14163                    SelectionGoal::None,
14164                )
14165            });
14166        })
14167    }
14168
14169    pub fn select_to_start_of_next_excerpt(
14170        &mut self,
14171        _: &SelectToStartOfNextExcerpt,
14172        window: &mut Window,
14173        cx: &mut Context<Self>,
14174    ) {
14175        if matches!(self.mode, EditorMode::SingleLine) {
14176            cx.propagate();
14177            return;
14178        }
14179        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14180        self.change_selections(Default::default(), window, cx, |s| {
14181            s.move_heads_with(|map, head, _| {
14182                (
14183                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14184                    SelectionGoal::None,
14185                )
14186            });
14187        })
14188    }
14189
14190    pub fn select_to_end_of_excerpt(
14191        &mut self,
14192        _: &SelectToEndOfExcerpt,
14193        window: &mut Window,
14194        cx: &mut Context<Self>,
14195    ) {
14196        if matches!(self.mode, EditorMode::SingleLine) {
14197            cx.propagate();
14198            return;
14199        }
14200        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14201        self.change_selections(Default::default(), window, cx, |s| {
14202            s.move_heads_with(|map, head, _| {
14203                (
14204                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14205                    SelectionGoal::None,
14206                )
14207            });
14208        })
14209    }
14210
14211    pub fn select_to_end_of_previous_excerpt(
14212        &mut self,
14213        _: &SelectToEndOfPreviousExcerpt,
14214        window: &mut Window,
14215        cx: &mut Context<Self>,
14216    ) {
14217        if matches!(self.mode, EditorMode::SingleLine) {
14218            cx.propagate();
14219            return;
14220        }
14221        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14222        self.change_selections(Default::default(), window, cx, |s| {
14223            s.move_heads_with(|map, head, _| {
14224                (
14225                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14226                    SelectionGoal::None,
14227                )
14228            });
14229        })
14230    }
14231
14232    pub fn move_to_beginning(
14233        &mut self,
14234        _: &MoveToBeginning,
14235        window: &mut Window,
14236        cx: &mut Context<Self>,
14237    ) {
14238        if matches!(self.mode, EditorMode::SingleLine) {
14239            cx.propagate();
14240            return;
14241        }
14242        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14243        self.change_selections(Default::default(), window, cx, |s| {
14244            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14245        });
14246    }
14247
14248    pub fn select_to_beginning(
14249        &mut self,
14250        _: &SelectToBeginning,
14251        window: &mut Window,
14252        cx: &mut Context<Self>,
14253    ) {
14254        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14255        selection.set_head(Point::zero(), SelectionGoal::None);
14256        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14257        self.change_selections(Default::default(), window, cx, |s| {
14258            s.select(vec![selection]);
14259        });
14260    }
14261
14262    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14263        if matches!(self.mode, EditorMode::SingleLine) {
14264            cx.propagate();
14265            return;
14266        }
14267        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14268        let cursor = self.buffer.read(cx).read(cx).len();
14269        self.change_selections(Default::default(), window, cx, |s| {
14270            s.select_ranges(vec![cursor..cursor])
14271        });
14272    }
14273
14274    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14275        self.nav_history = nav_history;
14276    }
14277
14278    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14279        self.nav_history.as_ref()
14280    }
14281
14282    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14283        self.push_to_nav_history(
14284            self.selections.newest_anchor().head(),
14285            None,
14286            false,
14287            true,
14288            cx,
14289        );
14290    }
14291
14292    fn push_to_nav_history(
14293        &mut self,
14294        cursor_anchor: Anchor,
14295        new_position: Option<Point>,
14296        is_deactivate: bool,
14297        always: bool,
14298        cx: &mut Context<Self>,
14299    ) {
14300        if let Some(nav_history) = self.nav_history.as_mut() {
14301            let buffer = self.buffer.read(cx).read(cx);
14302            let cursor_position = cursor_anchor.to_point(&buffer);
14303            let scroll_state = self.scroll_manager.anchor();
14304            let scroll_top_row = scroll_state.top_row(&buffer);
14305            drop(buffer);
14306
14307            if let Some(new_position) = new_position {
14308                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14309                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14310                    return;
14311                }
14312            }
14313
14314            nav_history.push(
14315                Some(NavigationData {
14316                    cursor_anchor,
14317                    cursor_position,
14318                    scroll_anchor: scroll_state,
14319                    scroll_top_row,
14320                }),
14321                cx,
14322            );
14323            cx.emit(EditorEvent::PushedToNavHistory {
14324                anchor: cursor_anchor,
14325                is_deactivate,
14326            })
14327        }
14328    }
14329
14330    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14331        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14332        let buffer = self.buffer.read(cx).snapshot(cx);
14333        let mut selection = self
14334            .selections
14335            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14336        selection.set_head(buffer.len(), SelectionGoal::None);
14337        self.change_selections(Default::default(), window, cx, |s| {
14338            s.select(vec![selection]);
14339        });
14340    }
14341
14342    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14343        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14344        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14345            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14346        });
14347    }
14348
14349    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14350        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14351        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14352        let mut selections = self.selections.all::<Point>(&display_map);
14353        let max_point = display_map.buffer_snapshot().max_point();
14354        for selection in &mut selections {
14355            let rows = selection.spanned_rows(true, &display_map);
14356            selection.start = Point::new(rows.start.0, 0);
14357            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14358            selection.reversed = false;
14359        }
14360        self.change_selections(Default::default(), window, cx, |s| {
14361            s.select(selections);
14362        });
14363    }
14364
14365    pub fn split_selection_into_lines(
14366        &mut self,
14367        action: &SplitSelectionIntoLines,
14368        window: &mut Window,
14369        cx: &mut Context<Self>,
14370    ) {
14371        let selections = self
14372            .selections
14373            .all::<Point>(&self.display_snapshot(cx))
14374            .into_iter()
14375            .map(|selection| selection.start..selection.end)
14376            .collect::<Vec<_>>();
14377        self.unfold_ranges(&selections, true, true, cx);
14378
14379        let mut new_selection_ranges = Vec::new();
14380        {
14381            let buffer = self.buffer.read(cx).read(cx);
14382            for selection in selections {
14383                for row in selection.start.row..selection.end.row {
14384                    let line_start = Point::new(row, 0);
14385                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14386
14387                    if action.keep_selections {
14388                        // Keep the selection range for each line
14389                        let selection_start = if row == selection.start.row {
14390                            selection.start
14391                        } else {
14392                            line_start
14393                        };
14394                        new_selection_ranges.push(selection_start..line_end);
14395                    } else {
14396                        // Collapse to cursor at end of line
14397                        new_selection_ranges.push(line_end..line_end);
14398                    }
14399                }
14400
14401                let is_multiline_selection = selection.start.row != selection.end.row;
14402                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14403                // so this action feels more ergonomic when paired with other selection operations
14404                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14405                if !should_skip_last {
14406                    if action.keep_selections {
14407                        if is_multiline_selection {
14408                            let line_start = Point::new(selection.end.row, 0);
14409                            new_selection_ranges.push(line_start..selection.end);
14410                        } else {
14411                            new_selection_ranges.push(selection.start..selection.end);
14412                        }
14413                    } else {
14414                        new_selection_ranges.push(selection.end..selection.end);
14415                    }
14416                }
14417            }
14418        }
14419        self.change_selections(Default::default(), window, cx, |s| {
14420            s.select_ranges(new_selection_ranges);
14421        });
14422    }
14423
14424    pub fn add_selection_above(
14425        &mut self,
14426        action: &AddSelectionAbove,
14427        window: &mut Window,
14428        cx: &mut Context<Self>,
14429    ) {
14430        self.add_selection(true, action.skip_soft_wrap, window, cx);
14431    }
14432
14433    pub fn add_selection_below(
14434        &mut self,
14435        action: &AddSelectionBelow,
14436        window: &mut Window,
14437        cx: &mut Context<Self>,
14438    ) {
14439        self.add_selection(false, action.skip_soft_wrap, window, cx);
14440    }
14441
14442    fn add_selection(
14443        &mut self,
14444        above: bool,
14445        skip_soft_wrap: bool,
14446        window: &mut Window,
14447        cx: &mut Context<Self>,
14448    ) {
14449        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14450
14451        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14452        let all_selections = self.selections.all::<Point>(&display_map);
14453        let text_layout_details = self.text_layout_details(window);
14454
14455        let (mut columnar_selections, new_selections_to_columnarize) = {
14456            if let Some(state) = self.add_selections_state.as_ref() {
14457                let columnar_selection_ids: HashSet<_> = state
14458                    .groups
14459                    .iter()
14460                    .flat_map(|group| group.stack.iter())
14461                    .copied()
14462                    .collect();
14463
14464                all_selections
14465                    .into_iter()
14466                    .partition(|s| columnar_selection_ids.contains(&s.id))
14467            } else {
14468                (Vec::new(), all_selections)
14469            }
14470        };
14471
14472        let mut state = self
14473            .add_selections_state
14474            .take()
14475            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14476
14477        for selection in new_selections_to_columnarize {
14478            let range = selection.display_range(&display_map).sorted();
14479            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14480            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14481            let positions = start_x.min(end_x)..start_x.max(end_x);
14482            let mut stack = Vec::new();
14483            for row in range.start.row().0..=range.end.row().0 {
14484                if let Some(selection) = self.selections.build_columnar_selection(
14485                    &display_map,
14486                    DisplayRow(row),
14487                    &positions,
14488                    selection.reversed,
14489                    &text_layout_details,
14490                ) {
14491                    stack.push(selection.id);
14492                    columnar_selections.push(selection);
14493                }
14494            }
14495            if !stack.is_empty() {
14496                if above {
14497                    stack.reverse();
14498                }
14499                state.groups.push(AddSelectionsGroup { above, stack });
14500            }
14501        }
14502
14503        let mut final_selections = Vec::new();
14504        let end_row = if above {
14505            DisplayRow(0)
14506        } else {
14507            display_map.max_point().row()
14508        };
14509
14510        let mut last_added_item_per_group = HashMap::default();
14511        for group in state.groups.iter_mut() {
14512            if let Some(last_id) = group.stack.last() {
14513                last_added_item_per_group.insert(*last_id, group);
14514            }
14515        }
14516
14517        for selection in columnar_selections {
14518            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14519                if above == group.above {
14520                    let range = selection.display_range(&display_map).sorted();
14521                    debug_assert_eq!(range.start.row(), range.end.row());
14522                    let mut row = range.start.row();
14523                    let positions =
14524                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14525                            Pixels::from(start)..Pixels::from(end)
14526                        } else {
14527                            let start_x =
14528                                display_map.x_for_display_point(range.start, &text_layout_details);
14529                            let end_x =
14530                                display_map.x_for_display_point(range.end, &text_layout_details);
14531                            start_x.min(end_x)..start_x.max(end_x)
14532                        };
14533
14534                    let mut maybe_new_selection = None;
14535                    let direction = if above { -1 } else { 1 };
14536
14537                    while row != end_row {
14538                        if skip_soft_wrap {
14539                            row = display_map
14540                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14541                                .row();
14542                        } else if above {
14543                            row.0 -= 1;
14544                        } else {
14545                            row.0 += 1;
14546                        }
14547
14548                        if let Some(new_selection) = self.selections.build_columnar_selection(
14549                            &display_map,
14550                            row,
14551                            &positions,
14552                            selection.reversed,
14553                            &text_layout_details,
14554                        ) {
14555                            maybe_new_selection = Some(new_selection);
14556                            break;
14557                        }
14558                    }
14559
14560                    if let Some(new_selection) = maybe_new_selection {
14561                        group.stack.push(new_selection.id);
14562                        if above {
14563                            final_selections.push(new_selection);
14564                            final_selections.push(selection);
14565                        } else {
14566                            final_selections.push(selection);
14567                            final_selections.push(new_selection);
14568                        }
14569                    } else {
14570                        final_selections.push(selection);
14571                    }
14572                } else {
14573                    group.stack.pop();
14574                }
14575            } else {
14576                final_selections.push(selection);
14577            }
14578        }
14579
14580        self.change_selections(Default::default(), window, cx, |s| {
14581            s.select(final_selections);
14582        });
14583
14584        let final_selection_ids: HashSet<_> = self
14585            .selections
14586            .all::<Point>(&display_map)
14587            .iter()
14588            .map(|s| s.id)
14589            .collect();
14590        state.groups.retain_mut(|group| {
14591            // selections might get merged above so we remove invalid items from stacks
14592            group.stack.retain(|id| final_selection_ids.contains(id));
14593
14594            // single selection in stack can be treated as initial state
14595            group.stack.len() > 1
14596        });
14597
14598        if !state.groups.is_empty() {
14599            self.add_selections_state = Some(state);
14600        }
14601    }
14602
14603    fn select_match_ranges(
14604        &mut self,
14605        range: Range<MultiBufferOffset>,
14606        reversed: bool,
14607        replace_newest: bool,
14608        auto_scroll: Option<Autoscroll>,
14609        window: &mut Window,
14610        cx: &mut Context<Editor>,
14611    ) {
14612        self.unfold_ranges(
14613            std::slice::from_ref(&range),
14614            false,
14615            auto_scroll.is_some(),
14616            cx,
14617        );
14618        let effects = if let Some(scroll) = auto_scroll {
14619            SelectionEffects::scroll(scroll)
14620        } else {
14621            SelectionEffects::no_scroll()
14622        };
14623        self.change_selections(effects, window, cx, |s| {
14624            if replace_newest {
14625                s.delete(s.newest_anchor().id);
14626            }
14627            if reversed {
14628                s.insert_range(range.end..range.start);
14629            } else {
14630                s.insert_range(range);
14631            }
14632        });
14633    }
14634
14635    pub fn select_next_match_internal(
14636        &mut self,
14637        display_map: &DisplaySnapshot,
14638        replace_newest: bool,
14639        autoscroll: Option<Autoscroll>,
14640        window: &mut Window,
14641        cx: &mut Context<Self>,
14642    ) -> Result<()> {
14643        let buffer = display_map.buffer_snapshot();
14644        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14645        if let Some(mut select_next_state) = self.select_next_state.take() {
14646            let query = &select_next_state.query;
14647            if !select_next_state.done {
14648                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14649                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14650                let mut next_selected_range = None;
14651
14652                let bytes_after_last_selection =
14653                    buffer.bytes_in_range(last_selection.end..buffer.len());
14654                let bytes_before_first_selection =
14655                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
14656                let query_matches = query
14657                    .stream_find_iter(bytes_after_last_selection)
14658                    .map(|result| (last_selection.end, result))
14659                    .chain(
14660                        query
14661                            .stream_find_iter(bytes_before_first_selection)
14662                            .map(|result| (MultiBufferOffset(0), result)),
14663                    );
14664
14665                for (start_offset, query_match) in query_matches {
14666                    let query_match = query_match.unwrap(); // can only fail due to I/O
14667                    let offset_range =
14668                        start_offset + query_match.start()..start_offset + query_match.end();
14669
14670                    if !select_next_state.wordwise
14671                        || (!buffer.is_inside_word(offset_range.start, None)
14672                            && !buffer.is_inside_word(offset_range.end, None))
14673                    {
14674                        let idx = selections
14675                            .partition_point(|selection| selection.end <= offset_range.start);
14676                        let overlaps = selections
14677                            .get(idx)
14678                            .map_or(false, |selection| selection.start < offset_range.end);
14679
14680                        if !overlaps {
14681                            next_selected_range = Some(offset_range);
14682                            break;
14683                        }
14684                    }
14685                }
14686
14687                if let Some(next_selected_range) = next_selected_range {
14688                    self.select_match_ranges(
14689                        next_selected_range,
14690                        last_selection.reversed,
14691                        replace_newest,
14692                        autoscroll,
14693                        window,
14694                        cx,
14695                    );
14696                } else {
14697                    select_next_state.done = true;
14698                }
14699            }
14700
14701            self.select_next_state = Some(select_next_state);
14702        } else {
14703            let mut only_carets = true;
14704            let mut same_text_selected = true;
14705            let mut selected_text = None;
14706
14707            let mut selections_iter = selections.iter().peekable();
14708            while let Some(selection) = selections_iter.next() {
14709                if selection.start != selection.end {
14710                    only_carets = false;
14711                }
14712
14713                if same_text_selected {
14714                    if selected_text.is_none() {
14715                        selected_text =
14716                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14717                    }
14718
14719                    if let Some(next_selection) = selections_iter.peek() {
14720                        if next_selection.len() == selection.len() {
14721                            let next_selected_text = buffer
14722                                .text_for_range(next_selection.range())
14723                                .collect::<String>();
14724                            if Some(next_selected_text) != selected_text {
14725                                same_text_selected = false;
14726                                selected_text = None;
14727                            }
14728                        } else {
14729                            same_text_selected = false;
14730                            selected_text = None;
14731                        }
14732                    }
14733                }
14734            }
14735
14736            if only_carets {
14737                for selection in &mut selections {
14738                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14739                    selection.start = word_range.start;
14740                    selection.end = word_range.end;
14741                    selection.goal = SelectionGoal::None;
14742                    selection.reversed = false;
14743                    self.select_match_ranges(
14744                        selection.start..selection.end,
14745                        selection.reversed,
14746                        replace_newest,
14747                        autoscroll,
14748                        window,
14749                        cx,
14750                    );
14751                }
14752
14753                if selections.len() == 1 {
14754                    let selection = selections
14755                        .last()
14756                        .expect("ensured that there's only one selection");
14757                    let query = buffer
14758                        .text_for_range(selection.start..selection.end)
14759                        .collect::<String>();
14760                    let is_empty = query.is_empty();
14761                    let select_state = SelectNextState {
14762                        query: self.build_query(&[query], cx)?,
14763                        wordwise: true,
14764                        done: is_empty,
14765                    };
14766                    self.select_next_state = Some(select_state);
14767                } else {
14768                    self.select_next_state = None;
14769                }
14770            } else if let Some(selected_text) = selected_text {
14771                self.select_next_state = Some(SelectNextState {
14772                    query: self.build_query(&[selected_text], cx)?,
14773                    wordwise: false,
14774                    done: false,
14775                });
14776                self.select_next_match_internal(
14777                    display_map,
14778                    replace_newest,
14779                    autoscroll,
14780                    window,
14781                    cx,
14782                )?;
14783            }
14784        }
14785        Ok(())
14786    }
14787
14788    pub fn select_all_matches(
14789        &mut self,
14790        _action: &SelectAllMatches,
14791        window: &mut Window,
14792        cx: &mut Context<Self>,
14793    ) -> Result<()> {
14794        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14795
14796        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14797
14798        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14799        let Some(select_next_state) = self.select_next_state.as_mut() else {
14800            return Ok(());
14801        };
14802        if select_next_state.done {
14803            return Ok(());
14804        }
14805
14806        let mut new_selections = Vec::new();
14807
14808        let reversed = self
14809            .selections
14810            .oldest::<MultiBufferOffset>(&display_map)
14811            .reversed;
14812        let buffer = display_map.buffer_snapshot();
14813        let query_matches = select_next_state
14814            .query
14815            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
14816
14817        for query_match in query_matches.into_iter() {
14818            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14819            let offset_range = if reversed {
14820                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
14821            } else {
14822                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
14823            };
14824
14825            if !select_next_state.wordwise
14826                || (!buffer.is_inside_word(offset_range.start, None)
14827                    && !buffer.is_inside_word(offset_range.end, None))
14828            {
14829                new_selections.push(offset_range.start..offset_range.end);
14830            }
14831        }
14832
14833        select_next_state.done = true;
14834
14835        if new_selections.is_empty() {
14836            log::error!("bug: new_selections is empty in select_all_matches");
14837            return Ok(());
14838        }
14839
14840        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14841        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14842            selections.select_ranges(new_selections)
14843        });
14844
14845        Ok(())
14846    }
14847
14848    pub fn select_next(
14849        &mut self,
14850        action: &SelectNext,
14851        window: &mut Window,
14852        cx: &mut Context<Self>,
14853    ) -> Result<()> {
14854        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14855        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14856        self.select_next_match_internal(
14857            &display_map,
14858            action.replace_newest,
14859            Some(Autoscroll::newest()),
14860            window,
14861            cx,
14862        )?;
14863        Ok(())
14864    }
14865
14866    pub fn select_previous(
14867        &mut self,
14868        action: &SelectPrevious,
14869        window: &mut Window,
14870        cx: &mut Context<Self>,
14871    ) -> Result<()> {
14872        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14873        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14874        let buffer = display_map.buffer_snapshot();
14875        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14876        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14877            let query = &select_prev_state.query;
14878            if !select_prev_state.done {
14879                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14880                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14881                let mut next_selected_range = None;
14882                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14883                let bytes_before_last_selection =
14884                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
14885                let bytes_after_first_selection =
14886                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14887                let query_matches = query
14888                    .stream_find_iter(bytes_before_last_selection)
14889                    .map(|result| (last_selection.start, result))
14890                    .chain(
14891                        query
14892                            .stream_find_iter(bytes_after_first_selection)
14893                            .map(|result| (buffer.len(), result)),
14894                    );
14895                for (end_offset, query_match) in query_matches {
14896                    let query_match = query_match.unwrap(); // can only fail due to I/O
14897                    let offset_range =
14898                        end_offset - query_match.end()..end_offset - query_match.start();
14899
14900                    if !select_prev_state.wordwise
14901                        || (!buffer.is_inside_word(offset_range.start, None)
14902                            && !buffer.is_inside_word(offset_range.end, None))
14903                    {
14904                        next_selected_range = Some(offset_range);
14905                        break;
14906                    }
14907                }
14908
14909                if let Some(next_selected_range) = next_selected_range {
14910                    self.select_match_ranges(
14911                        next_selected_range,
14912                        last_selection.reversed,
14913                        action.replace_newest,
14914                        Some(Autoscroll::newest()),
14915                        window,
14916                        cx,
14917                    );
14918                } else {
14919                    select_prev_state.done = true;
14920                }
14921            }
14922
14923            self.select_prev_state = Some(select_prev_state);
14924        } else {
14925            let mut only_carets = true;
14926            let mut same_text_selected = true;
14927            let mut selected_text = None;
14928
14929            let mut selections_iter = selections.iter().peekable();
14930            while let Some(selection) = selections_iter.next() {
14931                if selection.start != selection.end {
14932                    only_carets = false;
14933                }
14934
14935                if same_text_selected {
14936                    if selected_text.is_none() {
14937                        selected_text =
14938                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14939                    }
14940
14941                    if let Some(next_selection) = selections_iter.peek() {
14942                        if next_selection.len() == selection.len() {
14943                            let next_selected_text = buffer
14944                                .text_for_range(next_selection.range())
14945                                .collect::<String>();
14946                            if Some(next_selected_text) != selected_text {
14947                                same_text_selected = false;
14948                                selected_text = None;
14949                            }
14950                        } else {
14951                            same_text_selected = false;
14952                            selected_text = None;
14953                        }
14954                    }
14955                }
14956            }
14957
14958            if only_carets {
14959                for selection in &mut selections {
14960                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14961                    selection.start = word_range.start;
14962                    selection.end = word_range.end;
14963                    selection.goal = SelectionGoal::None;
14964                    selection.reversed = false;
14965                    self.select_match_ranges(
14966                        selection.start..selection.end,
14967                        selection.reversed,
14968                        action.replace_newest,
14969                        Some(Autoscroll::newest()),
14970                        window,
14971                        cx,
14972                    );
14973                }
14974                if selections.len() == 1 {
14975                    let selection = selections
14976                        .last()
14977                        .expect("ensured that there's only one selection");
14978                    let query = buffer
14979                        .text_for_range(selection.start..selection.end)
14980                        .collect::<String>();
14981                    let is_empty = query.is_empty();
14982                    let select_state = SelectNextState {
14983                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
14984                        wordwise: true,
14985                        done: is_empty,
14986                    };
14987                    self.select_prev_state = Some(select_state);
14988                } else {
14989                    self.select_prev_state = None;
14990                }
14991            } else if let Some(selected_text) = selected_text {
14992                self.select_prev_state = Some(SelectNextState {
14993                    query: self
14994                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
14995                    wordwise: false,
14996                    done: false,
14997                });
14998                self.select_previous(action, window, cx)?;
14999            }
15000        }
15001        Ok(())
15002    }
15003
15004    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15005    /// setting the case sensitivity based on the global
15006    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15007    /// editor's settings.
15008    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15009    where
15010        I: IntoIterator<Item = P>,
15011        P: AsRef<[u8]>,
15012    {
15013        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
15014            || EditorSettings::get_global(cx).search.case_sensitive,
15015            |value| value,
15016        );
15017
15018        let mut builder = AhoCorasickBuilder::new();
15019        builder.ascii_case_insensitive(!case_sensitive);
15020        builder.build(patterns)
15021    }
15022
15023    pub fn find_next_match(
15024        &mut self,
15025        _: &FindNextMatch,
15026        window: &mut Window,
15027        cx: &mut Context<Self>,
15028    ) -> Result<()> {
15029        let selections = self.selections.disjoint_anchors_arc();
15030        match selections.first() {
15031            Some(first) if selections.len() >= 2 => {
15032                self.change_selections(Default::default(), window, cx, |s| {
15033                    s.select_ranges([first.range()]);
15034                });
15035            }
15036            _ => self.select_next(
15037                &SelectNext {
15038                    replace_newest: true,
15039                },
15040                window,
15041                cx,
15042            )?,
15043        }
15044        Ok(())
15045    }
15046
15047    pub fn find_previous_match(
15048        &mut self,
15049        _: &FindPreviousMatch,
15050        window: &mut Window,
15051        cx: &mut Context<Self>,
15052    ) -> Result<()> {
15053        let selections = self.selections.disjoint_anchors_arc();
15054        match selections.last() {
15055            Some(last) if selections.len() >= 2 => {
15056                self.change_selections(Default::default(), window, cx, |s| {
15057                    s.select_ranges([last.range()]);
15058                });
15059            }
15060            _ => self.select_previous(
15061                &SelectPrevious {
15062                    replace_newest: true,
15063                },
15064                window,
15065                cx,
15066            )?,
15067        }
15068        Ok(())
15069    }
15070
15071    pub fn toggle_comments(
15072        &mut self,
15073        action: &ToggleComments,
15074        window: &mut Window,
15075        cx: &mut Context<Self>,
15076    ) {
15077        if self.read_only(cx) {
15078            return;
15079        }
15080        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15081        let text_layout_details = &self.text_layout_details(window);
15082        self.transact(window, cx, |this, window, cx| {
15083            let mut selections = this
15084                .selections
15085                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15086            let mut edits = Vec::new();
15087            let mut selection_edit_ranges = Vec::new();
15088            let mut last_toggled_row = None;
15089            let snapshot = this.buffer.read(cx).read(cx);
15090            let empty_str: Arc<str> = Arc::default();
15091            let mut suffixes_inserted = Vec::new();
15092            let ignore_indent = action.ignore_indent;
15093
15094            fn comment_prefix_range(
15095                snapshot: &MultiBufferSnapshot,
15096                row: MultiBufferRow,
15097                comment_prefix: &str,
15098                comment_prefix_whitespace: &str,
15099                ignore_indent: bool,
15100            ) -> Range<Point> {
15101                let indent_size = if ignore_indent {
15102                    0
15103                } else {
15104                    snapshot.indent_size_for_line(row).len
15105                };
15106
15107                let start = Point::new(row.0, indent_size);
15108
15109                let mut line_bytes = snapshot
15110                    .bytes_in_range(start..snapshot.max_point())
15111                    .flatten()
15112                    .copied();
15113
15114                // If this line currently begins with the line comment prefix, then record
15115                // the range containing the prefix.
15116                if line_bytes
15117                    .by_ref()
15118                    .take(comment_prefix.len())
15119                    .eq(comment_prefix.bytes())
15120                {
15121                    // Include any whitespace that matches the comment prefix.
15122                    let matching_whitespace_len = line_bytes
15123                        .zip(comment_prefix_whitespace.bytes())
15124                        .take_while(|(a, b)| a == b)
15125                        .count() as u32;
15126                    let end = Point::new(
15127                        start.row,
15128                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15129                    );
15130                    start..end
15131                } else {
15132                    start..start
15133                }
15134            }
15135
15136            fn comment_suffix_range(
15137                snapshot: &MultiBufferSnapshot,
15138                row: MultiBufferRow,
15139                comment_suffix: &str,
15140                comment_suffix_has_leading_space: bool,
15141            ) -> Range<Point> {
15142                let end = Point::new(row.0, snapshot.line_len(row));
15143                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15144
15145                let mut line_end_bytes = snapshot
15146                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15147                    .flatten()
15148                    .copied();
15149
15150                let leading_space_len = if suffix_start_column > 0
15151                    && line_end_bytes.next() == Some(b' ')
15152                    && comment_suffix_has_leading_space
15153                {
15154                    1
15155                } else {
15156                    0
15157                };
15158
15159                // If this line currently begins with the line comment prefix, then record
15160                // the range containing the prefix.
15161                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15162                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15163                    start..end
15164                } else {
15165                    end..end
15166                }
15167            }
15168
15169            // TODO: Handle selections that cross excerpts
15170            for selection in &mut selections {
15171                let start_column = snapshot
15172                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15173                    .len;
15174                let language = if let Some(language) =
15175                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15176                {
15177                    language
15178                } else {
15179                    continue;
15180                };
15181
15182                selection_edit_ranges.clear();
15183
15184                // If multiple selections contain a given row, avoid processing that
15185                // row more than once.
15186                let mut start_row = MultiBufferRow(selection.start.row);
15187                if last_toggled_row == Some(start_row) {
15188                    start_row = start_row.next_row();
15189                }
15190                let end_row =
15191                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15192                        MultiBufferRow(selection.end.row - 1)
15193                    } else {
15194                        MultiBufferRow(selection.end.row)
15195                    };
15196                last_toggled_row = Some(end_row);
15197
15198                if start_row > end_row {
15199                    continue;
15200                }
15201
15202                // If the language has line comments, toggle those.
15203                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15204
15205                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15206                if ignore_indent {
15207                    full_comment_prefixes = full_comment_prefixes
15208                        .into_iter()
15209                        .map(|s| Arc::from(s.trim_end()))
15210                        .collect();
15211                }
15212
15213                if !full_comment_prefixes.is_empty() {
15214                    let first_prefix = full_comment_prefixes
15215                        .first()
15216                        .expect("prefixes is non-empty");
15217                    let prefix_trimmed_lengths = full_comment_prefixes
15218                        .iter()
15219                        .map(|p| p.trim_end_matches(' ').len())
15220                        .collect::<SmallVec<[usize; 4]>>();
15221
15222                    let mut all_selection_lines_are_comments = true;
15223
15224                    for row in start_row.0..=end_row.0 {
15225                        let row = MultiBufferRow(row);
15226                        if start_row < end_row && snapshot.is_line_blank(row) {
15227                            continue;
15228                        }
15229
15230                        let prefix_range = full_comment_prefixes
15231                            .iter()
15232                            .zip(prefix_trimmed_lengths.iter().copied())
15233                            .map(|(prefix, trimmed_prefix_len)| {
15234                                comment_prefix_range(
15235                                    snapshot.deref(),
15236                                    row,
15237                                    &prefix[..trimmed_prefix_len],
15238                                    &prefix[trimmed_prefix_len..],
15239                                    ignore_indent,
15240                                )
15241                            })
15242                            .max_by_key(|range| range.end.column - range.start.column)
15243                            .expect("prefixes is non-empty");
15244
15245                        if prefix_range.is_empty() {
15246                            all_selection_lines_are_comments = false;
15247                        }
15248
15249                        selection_edit_ranges.push(prefix_range);
15250                    }
15251
15252                    if all_selection_lines_are_comments {
15253                        edits.extend(
15254                            selection_edit_ranges
15255                                .iter()
15256                                .cloned()
15257                                .map(|range| (range, empty_str.clone())),
15258                        );
15259                    } else {
15260                        let min_column = selection_edit_ranges
15261                            .iter()
15262                            .map(|range| range.start.column)
15263                            .min()
15264                            .unwrap_or(0);
15265                        edits.extend(selection_edit_ranges.iter().map(|range| {
15266                            let position = Point::new(range.start.row, min_column);
15267                            (position..position, first_prefix.clone())
15268                        }));
15269                    }
15270                } else if let Some(BlockCommentConfig {
15271                    start: full_comment_prefix,
15272                    end: comment_suffix,
15273                    ..
15274                }) = language.block_comment()
15275                {
15276                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15277                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15278                    let prefix_range = comment_prefix_range(
15279                        snapshot.deref(),
15280                        start_row,
15281                        comment_prefix,
15282                        comment_prefix_whitespace,
15283                        ignore_indent,
15284                    );
15285                    let suffix_range = comment_suffix_range(
15286                        snapshot.deref(),
15287                        end_row,
15288                        comment_suffix.trim_start_matches(' '),
15289                        comment_suffix.starts_with(' '),
15290                    );
15291
15292                    if prefix_range.is_empty() || suffix_range.is_empty() {
15293                        edits.push((
15294                            prefix_range.start..prefix_range.start,
15295                            full_comment_prefix.clone(),
15296                        ));
15297                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15298                        suffixes_inserted.push((end_row, comment_suffix.len()));
15299                    } else {
15300                        edits.push((prefix_range, empty_str.clone()));
15301                        edits.push((suffix_range, empty_str.clone()));
15302                    }
15303                } else {
15304                    continue;
15305                }
15306            }
15307
15308            drop(snapshot);
15309            this.buffer.update(cx, |buffer, cx| {
15310                buffer.edit(edits, None, cx);
15311            });
15312
15313            // Adjust selections so that they end before any comment suffixes that
15314            // were inserted.
15315            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15316            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15317            let snapshot = this.buffer.read(cx).read(cx);
15318            for selection in &mut selections {
15319                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15320                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15321                        Ordering::Less => {
15322                            suffixes_inserted.next();
15323                            continue;
15324                        }
15325                        Ordering::Greater => break,
15326                        Ordering::Equal => {
15327                            if selection.end.column == snapshot.line_len(row) {
15328                                if selection.is_empty() {
15329                                    selection.start.column -= suffix_len as u32;
15330                                }
15331                                selection.end.column -= suffix_len as u32;
15332                            }
15333                            break;
15334                        }
15335                    }
15336                }
15337            }
15338
15339            drop(snapshot);
15340            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15341
15342            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15343            let selections_on_single_row = selections.windows(2).all(|selections| {
15344                selections[0].start.row == selections[1].start.row
15345                    && selections[0].end.row == selections[1].end.row
15346                    && selections[0].start.row == selections[0].end.row
15347            });
15348            let selections_selecting = selections
15349                .iter()
15350                .any(|selection| selection.start != selection.end);
15351            let advance_downwards = action.advance_downwards
15352                && selections_on_single_row
15353                && !selections_selecting
15354                && !matches!(this.mode, EditorMode::SingleLine);
15355
15356            if advance_downwards {
15357                let snapshot = this.buffer.read(cx).snapshot(cx);
15358
15359                this.change_selections(Default::default(), window, cx, |s| {
15360                    s.move_cursors_with(|display_snapshot, display_point, _| {
15361                        let mut point = display_point.to_point(display_snapshot);
15362                        point.row += 1;
15363                        point = snapshot.clip_point(point, Bias::Left);
15364                        let display_point = point.to_display_point(display_snapshot);
15365                        let goal = SelectionGoal::HorizontalPosition(
15366                            display_snapshot
15367                                .x_for_display_point(display_point, text_layout_details)
15368                                .into(),
15369                        );
15370                        (display_point, goal)
15371                    })
15372                });
15373            }
15374        });
15375    }
15376
15377    pub fn select_enclosing_symbol(
15378        &mut self,
15379        _: &SelectEnclosingSymbol,
15380        window: &mut Window,
15381        cx: &mut Context<Self>,
15382    ) {
15383        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15384
15385        let buffer = self.buffer.read(cx).snapshot(cx);
15386        let old_selections = self
15387            .selections
15388            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15389            .into_boxed_slice();
15390
15391        fn update_selection(
15392            selection: &Selection<MultiBufferOffset>,
15393            buffer_snap: &MultiBufferSnapshot,
15394        ) -> Option<Selection<MultiBufferOffset>> {
15395            let cursor = selection.head();
15396            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15397            for symbol in symbols.iter().rev() {
15398                let start = symbol.range.start.to_offset(buffer_snap);
15399                let end = symbol.range.end.to_offset(buffer_snap);
15400                let new_range = start..end;
15401                if start < selection.start || end > selection.end {
15402                    return Some(Selection {
15403                        id: selection.id,
15404                        start: new_range.start,
15405                        end: new_range.end,
15406                        goal: SelectionGoal::None,
15407                        reversed: selection.reversed,
15408                    });
15409                }
15410            }
15411            None
15412        }
15413
15414        let mut selected_larger_symbol = false;
15415        let new_selections = old_selections
15416            .iter()
15417            .map(|selection| match update_selection(selection, &buffer) {
15418                Some(new_selection) => {
15419                    if new_selection.range() != selection.range() {
15420                        selected_larger_symbol = true;
15421                    }
15422                    new_selection
15423                }
15424                None => selection.clone(),
15425            })
15426            .collect::<Vec<_>>();
15427
15428        if selected_larger_symbol {
15429            self.change_selections(Default::default(), window, cx, |s| {
15430                s.select(new_selections);
15431            });
15432        }
15433    }
15434
15435    pub fn select_larger_syntax_node(
15436        &mut self,
15437        _: &SelectLargerSyntaxNode,
15438        window: &mut Window,
15439        cx: &mut Context<Self>,
15440    ) {
15441        let Some(visible_row_count) = self.visible_row_count() else {
15442            return;
15443        };
15444        let old_selections: Box<[_]> = self
15445            .selections
15446            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15447            .into();
15448        if old_selections.is_empty() {
15449            return;
15450        }
15451
15452        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15453
15454        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15455        let buffer = self.buffer.read(cx).snapshot(cx);
15456
15457        let mut selected_larger_node = false;
15458        let mut new_selections = old_selections
15459            .iter()
15460            .map(|selection| {
15461                let old_range = selection.start..selection.end;
15462
15463                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15464                    // manually select word at selection
15465                    if ["string_content", "inline"].contains(&node.kind()) {
15466                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15467                        // ignore if word is already selected
15468                        if !word_range.is_empty() && old_range != word_range {
15469                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15470                            // only select word if start and end point belongs to same word
15471                            if word_range == last_word_range {
15472                                selected_larger_node = true;
15473                                return Selection {
15474                                    id: selection.id,
15475                                    start: word_range.start,
15476                                    end: word_range.end,
15477                                    goal: SelectionGoal::None,
15478                                    reversed: selection.reversed,
15479                                };
15480                            }
15481                        }
15482                    }
15483                }
15484
15485                let mut new_range = old_range.clone();
15486                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15487                    new_range = range;
15488                    if !node.is_named() {
15489                        continue;
15490                    }
15491                    if !display_map.intersects_fold(new_range.start)
15492                        && !display_map.intersects_fold(new_range.end)
15493                    {
15494                        break;
15495                    }
15496                }
15497
15498                selected_larger_node |= new_range != old_range;
15499                Selection {
15500                    id: selection.id,
15501                    start: new_range.start,
15502                    end: new_range.end,
15503                    goal: SelectionGoal::None,
15504                    reversed: selection.reversed,
15505                }
15506            })
15507            .collect::<Vec<_>>();
15508
15509        if !selected_larger_node {
15510            return; // don't put this call in the history
15511        }
15512
15513        // scroll based on transformation done to the last selection created by the user
15514        let (last_old, last_new) = old_selections
15515            .last()
15516            .zip(new_selections.last().cloned())
15517            .expect("old_selections isn't empty");
15518
15519        // revert selection
15520        let is_selection_reversed = {
15521            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15522            new_selections.last_mut().expect("checked above").reversed =
15523                should_newest_selection_be_reversed;
15524            should_newest_selection_be_reversed
15525        };
15526
15527        if selected_larger_node {
15528            self.select_syntax_node_history.disable_clearing = true;
15529            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15530                s.select(new_selections.clone());
15531            });
15532            self.select_syntax_node_history.disable_clearing = false;
15533        }
15534
15535        let start_row = last_new.start.to_display_point(&display_map).row().0;
15536        let end_row = last_new.end.to_display_point(&display_map).row().0;
15537        let selection_height = end_row - start_row + 1;
15538        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15539
15540        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15541        let scroll_behavior = if fits_on_the_screen {
15542            self.request_autoscroll(Autoscroll::fit(), cx);
15543            SelectSyntaxNodeScrollBehavior::FitSelection
15544        } else if is_selection_reversed {
15545            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15546            SelectSyntaxNodeScrollBehavior::CursorTop
15547        } else {
15548            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15549            SelectSyntaxNodeScrollBehavior::CursorBottom
15550        };
15551
15552        self.select_syntax_node_history.push((
15553            old_selections,
15554            scroll_behavior,
15555            is_selection_reversed,
15556        ));
15557    }
15558
15559    pub fn select_smaller_syntax_node(
15560        &mut self,
15561        _: &SelectSmallerSyntaxNode,
15562        window: &mut Window,
15563        cx: &mut Context<Self>,
15564    ) {
15565        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15566
15567        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15568            self.select_syntax_node_history.pop()
15569        {
15570            if let Some(selection) = selections.last_mut() {
15571                selection.reversed = is_selection_reversed;
15572            }
15573
15574            self.select_syntax_node_history.disable_clearing = true;
15575            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15576                s.select(selections.to_vec());
15577            });
15578            self.select_syntax_node_history.disable_clearing = false;
15579
15580            match scroll_behavior {
15581                SelectSyntaxNodeScrollBehavior::CursorTop => {
15582                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15583                }
15584                SelectSyntaxNodeScrollBehavior::FitSelection => {
15585                    self.request_autoscroll(Autoscroll::fit(), cx);
15586                }
15587                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15588                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15589                }
15590            }
15591        }
15592    }
15593
15594    pub fn unwrap_syntax_node(
15595        &mut self,
15596        _: &UnwrapSyntaxNode,
15597        window: &mut Window,
15598        cx: &mut Context<Self>,
15599    ) {
15600        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15601
15602        let buffer = self.buffer.read(cx).snapshot(cx);
15603        let selections = self
15604            .selections
15605            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15606            .into_iter()
15607            // subtracting the offset requires sorting
15608            .sorted_by_key(|i| i.start);
15609
15610        let full_edits = selections
15611            .into_iter()
15612            .filter_map(|selection| {
15613                let child = if selection.is_empty()
15614                    && let Some((_, ancestor_range)) =
15615                        buffer.syntax_ancestor(selection.start..selection.end)
15616                {
15617                    ancestor_range
15618                } else {
15619                    selection.range()
15620                };
15621
15622                let mut parent = child.clone();
15623                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15624                    parent = ancestor_range;
15625                    if parent.start < child.start || parent.end > child.end {
15626                        break;
15627                    }
15628                }
15629
15630                if parent == child {
15631                    return None;
15632                }
15633                let text = buffer.text_for_range(child).collect::<String>();
15634                Some((selection.id, parent, text))
15635            })
15636            .collect::<Vec<_>>();
15637        if full_edits.is_empty() {
15638            return;
15639        }
15640
15641        self.transact(window, cx, |this, window, cx| {
15642            this.buffer.update(cx, |buffer, cx| {
15643                buffer.edit(
15644                    full_edits
15645                        .iter()
15646                        .map(|(_, p, t)| (p.clone(), t.clone()))
15647                        .collect::<Vec<_>>(),
15648                    None,
15649                    cx,
15650                );
15651            });
15652            this.change_selections(Default::default(), window, cx, |s| {
15653                let mut offset = 0;
15654                let mut selections = vec![];
15655                for (id, parent, text) in full_edits {
15656                    let start = parent.start - offset;
15657                    offset += (parent.end - parent.start) - text.len();
15658                    selections.push(Selection {
15659                        id,
15660                        start,
15661                        end: start + text.len(),
15662                        reversed: false,
15663                        goal: Default::default(),
15664                    });
15665                }
15666                s.select(selections);
15667            });
15668        });
15669    }
15670
15671    pub fn select_next_syntax_node(
15672        &mut self,
15673        _: &SelectNextSyntaxNode,
15674        window: &mut Window,
15675        cx: &mut Context<Self>,
15676    ) {
15677        let old_selections: Box<[_]> = self
15678            .selections
15679            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15680            .into();
15681        if old_selections.is_empty() {
15682            return;
15683        }
15684
15685        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15686
15687        let buffer = self.buffer.read(cx).snapshot(cx);
15688        let mut selected_sibling = false;
15689
15690        let new_selections = old_selections
15691            .iter()
15692            .map(|selection| {
15693                let old_range = selection.start..selection.end;
15694
15695                let old_range =
15696                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15697                let excerpt = buffer.excerpt_containing(old_range.clone());
15698
15699                if let Some(mut excerpt) = excerpt
15700                    && let Some(node) = excerpt
15701                        .buffer()
15702                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
15703                {
15704                    let new_range = excerpt.map_range_from_buffer(
15705                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15706                    );
15707                    selected_sibling = true;
15708                    Selection {
15709                        id: selection.id,
15710                        start: new_range.start,
15711                        end: new_range.end,
15712                        goal: SelectionGoal::None,
15713                        reversed: selection.reversed,
15714                    }
15715                } else {
15716                    selection.clone()
15717                }
15718            })
15719            .collect::<Vec<_>>();
15720
15721        if selected_sibling {
15722            self.change_selections(
15723                SelectionEffects::scroll(Autoscroll::fit()),
15724                window,
15725                cx,
15726                |s| {
15727                    s.select(new_selections);
15728                },
15729            );
15730        }
15731    }
15732
15733    pub fn select_prev_syntax_node(
15734        &mut self,
15735        _: &SelectPreviousSyntaxNode,
15736        window: &mut Window,
15737        cx: &mut Context<Self>,
15738    ) {
15739        let old_selections: Box<[_]> = self
15740            .selections
15741            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15742            .into();
15743        if old_selections.is_empty() {
15744            return;
15745        }
15746
15747        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15748
15749        let buffer = self.buffer.read(cx).snapshot(cx);
15750        let mut selected_sibling = false;
15751
15752        let new_selections = old_selections
15753            .iter()
15754            .map(|selection| {
15755                let old_range = selection.start..selection.end;
15756                let old_range =
15757                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15758                let excerpt = buffer.excerpt_containing(old_range.clone());
15759
15760                if let Some(mut excerpt) = excerpt
15761                    && let Some(node) = excerpt
15762                        .buffer()
15763                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
15764                {
15765                    let new_range = excerpt.map_range_from_buffer(
15766                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15767                    );
15768                    selected_sibling = true;
15769                    Selection {
15770                        id: selection.id,
15771                        start: new_range.start,
15772                        end: new_range.end,
15773                        goal: SelectionGoal::None,
15774                        reversed: selection.reversed,
15775                    }
15776                } else {
15777                    selection.clone()
15778                }
15779            })
15780            .collect::<Vec<_>>();
15781
15782        if selected_sibling {
15783            self.change_selections(
15784                SelectionEffects::scroll(Autoscroll::fit()),
15785                window,
15786                cx,
15787                |s| {
15788                    s.select(new_selections);
15789                },
15790            );
15791        }
15792    }
15793
15794    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15795        if !EditorSettings::get_global(cx).gutter.runnables {
15796            self.clear_tasks();
15797            return Task::ready(());
15798        }
15799        let project = self.project().map(Entity::downgrade);
15800        let task_sources = self.lsp_task_sources(cx);
15801        let multi_buffer = self.buffer.downgrade();
15802        cx.spawn_in(window, async move |editor, cx| {
15803            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15804            let Some(project) = project.and_then(|p| p.upgrade()) else {
15805                return;
15806            };
15807            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15808                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15809            }) else {
15810                return;
15811            };
15812
15813            let hide_runnables = project
15814                .update(cx, |project, _| project.is_via_collab())
15815                .unwrap_or(true);
15816            if hide_runnables {
15817                return;
15818            }
15819            let new_rows =
15820                cx.background_spawn({
15821                    let snapshot = display_snapshot.clone();
15822                    async move {
15823                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15824                    }
15825                })
15826                    .await;
15827            let Ok(lsp_tasks) =
15828                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15829            else {
15830                return;
15831            };
15832            let lsp_tasks = lsp_tasks.await;
15833
15834            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15835                lsp_tasks
15836                    .into_iter()
15837                    .flat_map(|(kind, tasks)| {
15838                        tasks.into_iter().filter_map(move |(location, task)| {
15839                            Some((kind.clone(), location?, task))
15840                        })
15841                    })
15842                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15843                        let buffer = location.target.buffer;
15844                        let buffer_snapshot = buffer.read(cx).snapshot();
15845                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15846                            |(excerpt_id, snapshot, _)| {
15847                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15848                                    display_snapshot
15849                                        .buffer_snapshot()
15850                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15851                                } else {
15852                                    None
15853                                }
15854                            },
15855                        );
15856                        if let Some(offset) = offset {
15857                            let task_buffer_range =
15858                                location.target.range.to_point(&buffer_snapshot);
15859                            let context_buffer_range =
15860                                task_buffer_range.to_offset(&buffer_snapshot);
15861                            let context_range = BufferOffset(context_buffer_range.start)
15862                                ..BufferOffset(context_buffer_range.end);
15863
15864                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15865                                .or_insert_with(|| RunnableTasks {
15866                                    templates: Vec::new(),
15867                                    offset,
15868                                    column: task_buffer_range.start.column,
15869                                    extra_variables: HashMap::default(),
15870                                    context_range,
15871                                })
15872                                .templates
15873                                .push((kind, task.original_task().clone()));
15874                        }
15875
15876                        acc
15877                    })
15878            }) else {
15879                return;
15880            };
15881
15882            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15883                buffer.language_settings(cx).tasks.prefer_lsp
15884            }) else {
15885                return;
15886            };
15887
15888            let rows = Self::runnable_rows(
15889                project,
15890                display_snapshot,
15891                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15892                new_rows,
15893                cx.clone(),
15894            )
15895            .await;
15896            editor
15897                .update(cx, |editor, _| {
15898                    editor.clear_tasks();
15899                    for (key, mut value) in rows {
15900                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15901                            value.templates.extend(lsp_tasks.templates);
15902                        }
15903
15904                        editor.insert_tasks(key, value);
15905                    }
15906                    for (key, value) in lsp_tasks_by_rows {
15907                        editor.insert_tasks(key, value);
15908                    }
15909                })
15910                .ok();
15911        })
15912    }
15913    fn fetch_runnable_ranges(
15914        snapshot: &DisplaySnapshot,
15915        range: Range<Anchor>,
15916    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
15917        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15918    }
15919
15920    fn runnable_rows(
15921        project: Entity<Project>,
15922        snapshot: DisplaySnapshot,
15923        prefer_lsp: bool,
15924        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
15925        cx: AsyncWindowContext,
15926    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15927        cx.spawn(async move |cx| {
15928            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15929            for (run_range, mut runnable) in runnable_ranges {
15930                let Some(tasks) = cx
15931                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15932                    .ok()
15933                else {
15934                    continue;
15935                };
15936                let mut tasks = tasks.await;
15937
15938                if prefer_lsp {
15939                    tasks.retain(|(task_kind, _)| {
15940                        !matches!(task_kind, TaskSourceKind::Language { .. })
15941                    });
15942                }
15943                if tasks.is_empty() {
15944                    continue;
15945                }
15946
15947                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
15948                let Some(row) = snapshot
15949                    .buffer_snapshot()
15950                    .buffer_line_for_row(MultiBufferRow(point.row))
15951                    .map(|(_, range)| range.start.row)
15952                else {
15953                    continue;
15954                };
15955
15956                let context_range =
15957                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15958                runnable_rows.push((
15959                    (runnable.buffer_id, row),
15960                    RunnableTasks {
15961                        templates: tasks,
15962                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
15963                        context_range,
15964                        column: point.column,
15965                        extra_variables: runnable.extra_captures,
15966                    },
15967                ));
15968            }
15969            runnable_rows
15970        })
15971    }
15972
15973    fn templates_with_tags(
15974        project: &Entity<Project>,
15975        runnable: &mut Runnable,
15976        cx: &mut App,
15977    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15978        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15979            let (worktree_id, file) = project
15980                .buffer_for_id(runnable.buffer, cx)
15981                .and_then(|buffer| buffer.read(cx).file())
15982                .map(|file| (file.worktree_id(cx), file.clone()))
15983                .unzip();
15984
15985            (
15986                project.task_store().read(cx).task_inventory().cloned(),
15987                worktree_id,
15988                file,
15989            )
15990        });
15991
15992        let tags = mem::take(&mut runnable.tags);
15993        let language = runnable.language.clone();
15994        cx.spawn(async move |cx| {
15995            let mut templates_with_tags = Vec::new();
15996            if let Some(inventory) = inventory {
15997                for RunnableTag(tag) in tags {
15998                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15999                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16000                    }) else {
16001                        return templates_with_tags;
16002                    };
16003                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16004                        move |(_, template)| {
16005                            template.tags.iter().any(|source_tag| source_tag == &tag)
16006                        },
16007                    ));
16008                }
16009            }
16010            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16011
16012            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16013                // Strongest source wins; if we have worktree tag binding, prefer that to
16014                // global and language bindings;
16015                // if we have a global binding, prefer that to language binding.
16016                let first_mismatch = templates_with_tags
16017                    .iter()
16018                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16019                if let Some(index) = first_mismatch {
16020                    templates_with_tags.truncate(index);
16021                }
16022            }
16023
16024            templates_with_tags
16025        })
16026    }
16027
16028    pub fn move_to_enclosing_bracket(
16029        &mut self,
16030        _: &MoveToEnclosingBracket,
16031        window: &mut Window,
16032        cx: &mut Context<Self>,
16033    ) {
16034        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16035        self.change_selections(Default::default(), window, cx, |s| {
16036            s.move_offsets_with(|snapshot, selection| {
16037                let Some(enclosing_bracket_ranges) =
16038                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16039                else {
16040                    return;
16041                };
16042
16043                let mut best_length = usize::MAX;
16044                let mut best_inside = false;
16045                let mut best_in_bracket_range = false;
16046                let mut best_destination = None;
16047                for (open, close) in enclosing_bracket_ranges {
16048                    let close = close.to_inclusive();
16049                    let length = *close.end() - open.start;
16050                    let inside = selection.start >= open.end && selection.end <= *close.start();
16051                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16052                        || close.contains(&selection.head());
16053
16054                    // If best is next to a bracket and current isn't, skip
16055                    if !in_bracket_range && best_in_bracket_range {
16056                        continue;
16057                    }
16058
16059                    // Prefer smaller lengths unless best is inside and current isn't
16060                    if length > best_length && (best_inside || !inside) {
16061                        continue;
16062                    }
16063
16064                    best_length = length;
16065                    best_inside = inside;
16066                    best_in_bracket_range = in_bracket_range;
16067                    best_destination = Some(
16068                        if close.contains(&selection.start) && close.contains(&selection.end) {
16069                            if inside { open.end } else { open.start }
16070                        } else if inside {
16071                            *close.start()
16072                        } else {
16073                            *close.end()
16074                        },
16075                    );
16076                }
16077
16078                if let Some(destination) = best_destination {
16079                    selection.collapse_to(destination, SelectionGoal::None);
16080                }
16081            })
16082        });
16083    }
16084
16085    pub fn undo_selection(
16086        &mut self,
16087        _: &UndoSelection,
16088        window: &mut Window,
16089        cx: &mut Context<Self>,
16090    ) {
16091        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16092        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16093            self.selection_history.mode = SelectionHistoryMode::Undoing;
16094            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16095                this.end_selection(window, cx);
16096                this.change_selections(
16097                    SelectionEffects::scroll(Autoscroll::newest()),
16098                    window,
16099                    cx,
16100                    |s| s.select_anchors(entry.selections.to_vec()),
16101                );
16102            });
16103            self.selection_history.mode = SelectionHistoryMode::Normal;
16104
16105            self.select_next_state = entry.select_next_state;
16106            self.select_prev_state = entry.select_prev_state;
16107            self.add_selections_state = entry.add_selections_state;
16108        }
16109    }
16110
16111    pub fn redo_selection(
16112        &mut self,
16113        _: &RedoSelection,
16114        window: &mut Window,
16115        cx: &mut Context<Self>,
16116    ) {
16117        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16118        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16119            self.selection_history.mode = SelectionHistoryMode::Redoing;
16120            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16121                this.end_selection(window, cx);
16122                this.change_selections(
16123                    SelectionEffects::scroll(Autoscroll::newest()),
16124                    window,
16125                    cx,
16126                    |s| s.select_anchors(entry.selections.to_vec()),
16127                );
16128            });
16129            self.selection_history.mode = SelectionHistoryMode::Normal;
16130
16131            self.select_next_state = entry.select_next_state;
16132            self.select_prev_state = entry.select_prev_state;
16133            self.add_selections_state = entry.add_selections_state;
16134        }
16135    }
16136
16137    pub fn expand_excerpts(
16138        &mut self,
16139        action: &ExpandExcerpts,
16140        _: &mut Window,
16141        cx: &mut Context<Self>,
16142    ) {
16143        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16144    }
16145
16146    pub fn expand_excerpts_down(
16147        &mut self,
16148        action: &ExpandExcerptsDown,
16149        _: &mut Window,
16150        cx: &mut Context<Self>,
16151    ) {
16152        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16153    }
16154
16155    pub fn expand_excerpts_up(
16156        &mut self,
16157        action: &ExpandExcerptsUp,
16158        _: &mut Window,
16159        cx: &mut Context<Self>,
16160    ) {
16161        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16162    }
16163
16164    pub fn expand_excerpts_for_direction(
16165        &mut self,
16166        lines: u32,
16167        direction: ExpandExcerptDirection,
16168
16169        cx: &mut Context<Self>,
16170    ) {
16171        let selections = self.selections.disjoint_anchors_arc();
16172
16173        let lines = if lines == 0 {
16174            EditorSettings::get_global(cx).expand_excerpt_lines
16175        } else {
16176            lines
16177        };
16178
16179        self.buffer.update(cx, |buffer, cx| {
16180            let snapshot = buffer.snapshot(cx);
16181            let mut excerpt_ids = selections
16182                .iter()
16183                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16184                .collect::<Vec<_>>();
16185            excerpt_ids.sort();
16186            excerpt_ids.dedup();
16187            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16188        })
16189    }
16190
16191    pub fn expand_excerpt(
16192        &mut self,
16193        excerpt: ExcerptId,
16194        direction: ExpandExcerptDirection,
16195        window: &mut Window,
16196        cx: &mut Context<Self>,
16197    ) {
16198        let current_scroll_position = self.scroll_position(cx);
16199        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16200        let mut scroll = None;
16201
16202        if direction == ExpandExcerptDirection::Down {
16203            let multi_buffer = self.buffer.read(cx);
16204            let snapshot = multi_buffer.snapshot(cx);
16205            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16206                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16207                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16208            {
16209                let buffer_snapshot = buffer.read(cx).snapshot();
16210                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16211                let last_row = buffer_snapshot.max_point().row;
16212                let lines_below = last_row.saturating_sub(excerpt_end_row);
16213                if lines_below >= lines_to_expand {
16214                    scroll = Some(
16215                        current_scroll_position
16216                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16217                    );
16218                }
16219            }
16220        }
16221        if direction == ExpandExcerptDirection::Up
16222            && self
16223                .buffer
16224                .read(cx)
16225                .snapshot(cx)
16226                .excerpt_before(excerpt)
16227                .is_none()
16228        {
16229            scroll = Some(current_scroll_position);
16230        }
16231
16232        self.buffer.update(cx, |buffer, cx| {
16233            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16234        });
16235
16236        if let Some(new_scroll_position) = scroll {
16237            self.set_scroll_position(new_scroll_position, window, cx);
16238        }
16239    }
16240
16241    pub fn go_to_singleton_buffer_point(
16242        &mut self,
16243        point: Point,
16244        window: &mut Window,
16245        cx: &mut Context<Self>,
16246    ) {
16247        self.go_to_singleton_buffer_range(point..point, window, cx);
16248    }
16249
16250    pub fn go_to_singleton_buffer_range(
16251        &mut self,
16252        range: Range<Point>,
16253        window: &mut Window,
16254        cx: &mut Context<Self>,
16255    ) {
16256        let multibuffer = self.buffer().read(cx);
16257        let Some(buffer) = multibuffer.as_singleton() else {
16258            return;
16259        };
16260        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16261            return;
16262        };
16263        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16264            return;
16265        };
16266        self.change_selections(
16267            SelectionEffects::default().nav_history(true),
16268            window,
16269            cx,
16270            |s| s.select_anchor_ranges([start..end]),
16271        );
16272    }
16273
16274    pub fn go_to_diagnostic(
16275        &mut self,
16276        action: &GoToDiagnostic,
16277        window: &mut Window,
16278        cx: &mut Context<Self>,
16279    ) {
16280        if !self.diagnostics_enabled() {
16281            return;
16282        }
16283        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16284        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16285    }
16286
16287    pub fn go_to_prev_diagnostic(
16288        &mut self,
16289        action: &GoToPreviousDiagnostic,
16290        window: &mut Window,
16291        cx: &mut Context<Self>,
16292    ) {
16293        if !self.diagnostics_enabled() {
16294            return;
16295        }
16296        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16297        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16298    }
16299
16300    pub fn go_to_diagnostic_impl(
16301        &mut self,
16302        direction: Direction,
16303        severity: GoToDiagnosticSeverityFilter,
16304        window: &mut Window,
16305        cx: &mut Context<Self>,
16306    ) {
16307        let buffer = self.buffer.read(cx).snapshot(cx);
16308        let selection = self
16309            .selections
16310            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16311
16312        let mut active_group_id = None;
16313        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16314            && active_group.active_range.start.to_offset(&buffer) == selection.start
16315        {
16316            active_group_id = Some(active_group.group_id);
16317        }
16318
16319        fn filtered<'a>(
16320            severity: GoToDiagnosticSeverityFilter,
16321            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16322        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16323            diagnostics
16324                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16325                .filter(|entry| entry.range.start != entry.range.end)
16326                .filter(|entry| !entry.diagnostic.is_unnecessary)
16327        }
16328
16329        let before = filtered(
16330            severity,
16331            buffer
16332                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16333                .filter(|entry| entry.range.start <= selection.start),
16334        );
16335        let after = filtered(
16336            severity,
16337            buffer
16338                .diagnostics_in_range(selection.start..buffer.len())
16339                .filter(|entry| entry.range.start >= selection.start),
16340        );
16341
16342        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16343        if direction == Direction::Prev {
16344            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16345            {
16346                for diagnostic in prev_diagnostics.into_iter().rev() {
16347                    if diagnostic.range.start != selection.start
16348                        || active_group_id
16349                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16350                    {
16351                        found = Some(diagnostic);
16352                        break 'outer;
16353                    }
16354                }
16355            }
16356        } else {
16357            for diagnostic in after.chain(before) {
16358                if diagnostic.range.start != selection.start
16359                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16360                {
16361                    found = Some(diagnostic);
16362                    break;
16363                }
16364            }
16365        }
16366        let Some(next_diagnostic) = found else {
16367            return;
16368        };
16369
16370        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16371        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16372            return;
16373        };
16374        let snapshot = self.snapshot(window, cx);
16375        if snapshot.intersects_fold(next_diagnostic.range.start) {
16376            self.unfold_ranges(
16377                std::slice::from_ref(&next_diagnostic.range),
16378                true,
16379                false,
16380                cx,
16381            );
16382        }
16383        self.change_selections(Default::default(), window, cx, |s| {
16384            s.select_ranges(vec![
16385                next_diagnostic.range.start..next_diagnostic.range.start,
16386            ])
16387        });
16388        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16389        self.refresh_edit_prediction(false, true, window, cx);
16390    }
16391
16392    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16393        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16394        let snapshot = self.snapshot(window, cx);
16395        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16396        self.go_to_hunk_before_or_after_position(
16397            &snapshot,
16398            selection.head(),
16399            Direction::Next,
16400            window,
16401            cx,
16402        );
16403    }
16404
16405    pub fn go_to_hunk_before_or_after_position(
16406        &mut self,
16407        snapshot: &EditorSnapshot,
16408        position: Point,
16409        direction: Direction,
16410        window: &mut Window,
16411        cx: &mut Context<Editor>,
16412    ) {
16413        let row = if direction == Direction::Next {
16414            self.hunk_after_position(snapshot, position)
16415                .map(|hunk| hunk.row_range.start)
16416        } else {
16417            self.hunk_before_position(snapshot, position)
16418        };
16419
16420        if let Some(row) = row {
16421            let destination = Point::new(row.0, 0);
16422            let autoscroll = Autoscroll::center();
16423
16424            self.unfold_ranges(&[destination..destination], false, false, cx);
16425            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16426                s.select_ranges([destination..destination]);
16427            });
16428        }
16429    }
16430
16431    fn hunk_after_position(
16432        &mut self,
16433        snapshot: &EditorSnapshot,
16434        position: Point,
16435    ) -> Option<MultiBufferDiffHunk> {
16436        snapshot
16437            .buffer_snapshot()
16438            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16439            .find(|hunk| hunk.row_range.start.0 > position.row)
16440            .or_else(|| {
16441                snapshot
16442                    .buffer_snapshot()
16443                    .diff_hunks_in_range(Point::zero()..position)
16444                    .find(|hunk| hunk.row_range.end.0 < position.row)
16445            })
16446    }
16447
16448    fn go_to_prev_hunk(
16449        &mut self,
16450        _: &GoToPreviousHunk,
16451        window: &mut Window,
16452        cx: &mut Context<Self>,
16453    ) {
16454        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16455        let snapshot = self.snapshot(window, cx);
16456        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16457        self.go_to_hunk_before_or_after_position(
16458            &snapshot,
16459            selection.head(),
16460            Direction::Prev,
16461            window,
16462            cx,
16463        );
16464    }
16465
16466    fn hunk_before_position(
16467        &mut self,
16468        snapshot: &EditorSnapshot,
16469        position: Point,
16470    ) -> Option<MultiBufferRow> {
16471        snapshot
16472            .buffer_snapshot()
16473            .diff_hunk_before(position)
16474            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16475    }
16476
16477    fn go_to_next_change(
16478        &mut self,
16479        _: &GoToNextChange,
16480        window: &mut Window,
16481        cx: &mut Context<Self>,
16482    ) {
16483        if let Some(selections) = self
16484            .change_list
16485            .next_change(1, Direction::Next)
16486            .map(|s| s.to_vec())
16487        {
16488            self.change_selections(Default::default(), window, cx, |s| {
16489                let map = s.display_snapshot();
16490                s.select_display_ranges(selections.iter().map(|a| {
16491                    let point = a.to_display_point(&map);
16492                    point..point
16493                }))
16494            })
16495        }
16496    }
16497
16498    fn go_to_previous_change(
16499        &mut self,
16500        _: &GoToPreviousChange,
16501        window: &mut Window,
16502        cx: &mut Context<Self>,
16503    ) {
16504        if let Some(selections) = self
16505            .change_list
16506            .next_change(1, Direction::Prev)
16507            .map(|s| s.to_vec())
16508        {
16509            self.change_selections(Default::default(), window, cx, |s| {
16510                let map = s.display_snapshot();
16511                s.select_display_ranges(selections.iter().map(|a| {
16512                    let point = a.to_display_point(&map);
16513                    point..point
16514                }))
16515            })
16516        }
16517    }
16518
16519    pub fn go_to_next_document_highlight(
16520        &mut self,
16521        _: &GoToNextDocumentHighlight,
16522        window: &mut Window,
16523        cx: &mut Context<Self>,
16524    ) {
16525        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16526    }
16527
16528    pub fn go_to_prev_document_highlight(
16529        &mut self,
16530        _: &GoToPreviousDocumentHighlight,
16531        window: &mut Window,
16532        cx: &mut Context<Self>,
16533    ) {
16534        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16535    }
16536
16537    pub fn go_to_document_highlight_before_or_after_position(
16538        &mut self,
16539        direction: Direction,
16540        window: &mut Window,
16541        cx: &mut Context<Editor>,
16542    ) {
16543        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16544        let snapshot = self.snapshot(window, cx);
16545        let buffer = &snapshot.buffer_snapshot();
16546        let position = self
16547            .selections
16548            .newest::<Point>(&snapshot.display_snapshot)
16549            .head();
16550        let anchor_position = buffer.anchor_after(position);
16551
16552        // Get all document highlights (both read and write)
16553        let mut all_highlights = Vec::new();
16554
16555        if let Some((_, read_highlights)) = self
16556            .background_highlights
16557            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16558        {
16559            all_highlights.extend(read_highlights.iter());
16560        }
16561
16562        if let Some((_, write_highlights)) = self
16563            .background_highlights
16564            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16565        {
16566            all_highlights.extend(write_highlights.iter());
16567        }
16568
16569        if all_highlights.is_empty() {
16570            return;
16571        }
16572
16573        // Sort highlights by position
16574        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16575
16576        let target_highlight = match direction {
16577            Direction::Next => {
16578                // Find the first highlight after the current position
16579                all_highlights
16580                    .iter()
16581                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16582            }
16583            Direction::Prev => {
16584                // Find the last highlight before the current position
16585                all_highlights
16586                    .iter()
16587                    .rev()
16588                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16589            }
16590        };
16591
16592        if let Some(highlight) = target_highlight {
16593            let destination = highlight.start.to_point(buffer);
16594            let autoscroll = Autoscroll::center();
16595
16596            self.unfold_ranges(&[destination..destination], false, false, cx);
16597            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16598                s.select_ranges([destination..destination]);
16599            });
16600        }
16601    }
16602
16603    fn go_to_line<T: 'static>(
16604        &mut self,
16605        position: Anchor,
16606        highlight_color: Option<Hsla>,
16607        window: &mut Window,
16608        cx: &mut Context<Self>,
16609    ) {
16610        let snapshot = self.snapshot(window, cx).display_snapshot;
16611        let position = position.to_point(&snapshot.buffer_snapshot());
16612        let start = snapshot
16613            .buffer_snapshot()
16614            .clip_point(Point::new(position.row, 0), Bias::Left);
16615        let end = start + Point::new(1, 0);
16616        let start = snapshot.buffer_snapshot().anchor_before(start);
16617        let end = snapshot.buffer_snapshot().anchor_before(end);
16618
16619        self.highlight_rows::<T>(
16620            start..end,
16621            highlight_color
16622                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16623            Default::default(),
16624            cx,
16625        );
16626
16627        if self.buffer.read(cx).is_singleton() {
16628            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16629        }
16630    }
16631
16632    pub fn go_to_definition(
16633        &mut self,
16634        _: &GoToDefinition,
16635        window: &mut Window,
16636        cx: &mut Context<Self>,
16637    ) -> Task<Result<Navigated>> {
16638        let definition =
16639            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16640        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16641        cx.spawn_in(window, async move |editor, cx| {
16642            if definition.await? == Navigated::Yes {
16643                return Ok(Navigated::Yes);
16644            }
16645            match fallback_strategy {
16646                GoToDefinitionFallback::None => Ok(Navigated::No),
16647                GoToDefinitionFallback::FindAllReferences => {
16648                    match editor.update_in(cx, |editor, window, cx| {
16649                        editor.find_all_references(&FindAllReferences, window, cx)
16650                    })? {
16651                        Some(references) => references.await,
16652                        None => Ok(Navigated::No),
16653                    }
16654                }
16655            }
16656        })
16657    }
16658
16659    pub fn go_to_declaration(
16660        &mut self,
16661        _: &GoToDeclaration,
16662        window: &mut Window,
16663        cx: &mut Context<Self>,
16664    ) -> Task<Result<Navigated>> {
16665        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16666    }
16667
16668    pub fn go_to_declaration_split(
16669        &mut self,
16670        _: &GoToDeclaration,
16671        window: &mut Window,
16672        cx: &mut Context<Self>,
16673    ) -> Task<Result<Navigated>> {
16674        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16675    }
16676
16677    pub fn go_to_implementation(
16678        &mut self,
16679        _: &GoToImplementation,
16680        window: &mut Window,
16681        cx: &mut Context<Self>,
16682    ) -> Task<Result<Navigated>> {
16683        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16684    }
16685
16686    pub fn go_to_implementation_split(
16687        &mut self,
16688        _: &GoToImplementationSplit,
16689        window: &mut Window,
16690        cx: &mut Context<Self>,
16691    ) -> Task<Result<Navigated>> {
16692        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16693    }
16694
16695    pub fn go_to_type_definition(
16696        &mut self,
16697        _: &GoToTypeDefinition,
16698        window: &mut Window,
16699        cx: &mut Context<Self>,
16700    ) -> Task<Result<Navigated>> {
16701        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16702    }
16703
16704    pub fn go_to_definition_split(
16705        &mut self,
16706        _: &GoToDefinitionSplit,
16707        window: &mut Window,
16708        cx: &mut Context<Self>,
16709    ) -> Task<Result<Navigated>> {
16710        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16711    }
16712
16713    pub fn go_to_type_definition_split(
16714        &mut self,
16715        _: &GoToTypeDefinitionSplit,
16716        window: &mut Window,
16717        cx: &mut Context<Self>,
16718    ) -> Task<Result<Navigated>> {
16719        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16720    }
16721
16722    fn go_to_definition_of_kind(
16723        &mut self,
16724        kind: GotoDefinitionKind,
16725        split: bool,
16726        window: &mut Window,
16727        cx: &mut Context<Self>,
16728    ) -> Task<Result<Navigated>> {
16729        let Some(provider) = self.semantics_provider.clone() else {
16730            return Task::ready(Ok(Navigated::No));
16731        };
16732        let head = self
16733            .selections
16734            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
16735            .head();
16736        let buffer = self.buffer.read(cx);
16737        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16738            return Task::ready(Ok(Navigated::No));
16739        };
16740        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16741            return Task::ready(Ok(Navigated::No));
16742        };
16743
16744        cx.spawn_in(window, async move |editor, cx| {
16745            let Some(definitions) = definitions.await? else {
16746                return Ok(Navigated::No);
16747            };
16748            let navigated = editor
16749                .update_in(cx, |editor, window, cx| {
16750                    editor.navigate_to_hover_links(
16751                        Some(kind),
16752                        definitions
16753                            .into_iter()
16754                            .filter(|location| {
16755                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16756                            })
16757                            .map(HoverLink::Text)
16758                            .collect::<Vec<_>>(),
16759                        split,
16760                        window,
16761                        cx,
16762                    )
16763                })?
16764                .await?;
16765            anyhow::Ok(navigated)
16766        })
16767    }
16768
16769    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16770        let selection = self.selections.newest_anchor();
16771        let head = selection.head();
16772        let tail = selection.tail();
16773
16774        let Some((buffer, start_position)) =
16775            self.buffer.read(cx).text_anchor_for_position(head, cx)
16776        else {
16777            return;
16778        };
16779
16780        let end_position = if head != tail {
16781            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16782                return;
16783            };
16784            Some(pos)
16785        } else {
16786            None
16787        };
16788
16789        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16790            let url = if let Some(end_pos) = end_position {
16791                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16792            } else {
16793                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16794            };
16795
16796            if let Some(url) = url {
16797                cx.update(|window, cx| {
16798                    if parse_zed_link(&url, cx).is_some() {
16799                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16800                    } else {
16801                        cx.open_url(&url);
16802                    }
16803                })?;
16804            }
16805
16806            anyhow::Ok(())
16807        });
16808
16809        url_finder.detach();
16810    }
16811
16812    pub fn open_selected_filename(
16813        &mut self,
16814        _: &OpenSelectedFilename,
16815        window: &mut Window,
16816        cx: &mut Context<Self>,
16817    ) {
16818        let Some(workspace) = self.workspace() else {
16819            return;
16820        };
16821
16822        let position = self.selections.newest_anchor().head();
16823
16824        let Some((buffer, buffer_position)) =
16825            self.buffer.read(cx).text_anchor_for_position(position, cx)
16826        else {
16827            return;
16828        };
16829
16830        let project = self.project.clone();
16831
16832        cx.spawn_in(window, async move |_, cx| {
16833            let result = find_file(&buffer, project, buffer_position, cx).await;
16834
16835            if let Some((_, path)) = result {
16836                workspace
16837                    .update_in(cx, |workspace, window, cx| {
16838                        workspace.open_resolved_path(path, window, cx)
16839                    })?
16840                    .await?;
16841            }
16842            anyhow::Ok(())
16843        })
16844        .detach();
16845    }
16846
16847    pub(crate) fn navigate_to_hover_links(
16848        &mut self,
16849        kind: Option<GotoDefinitionKind>,
16850        definitions: Vec<HoverLink>,
16851        split: bool,
16852        window: &mut Window,
16853        cx: &mut Context<Editor>,
16854    ) -> Task<Result<Navigated>> {
16855        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16856        let mut first_url_or_file = None;
16857        let definitions: Vec<_> = definitions
16858            .into_iter()
16859            .filter_map(|def| match def {
16860                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16861                HoverLink::InlayHint(lsp_location, server_id) => {
16862                    let computation =
16863                        self.compute_target_location(lsp_location, server_id, window, cx);
16864                    Some(cx.background_spawn(computation))
16865                }
16866                HoverLink::Url(url) => {
16867                    first_url_or_file = Some(Either::Left(url));
16868                    None
16869                }
16870                HoverLink::File(path) => {
16871                    first_url_or_file = Some(Either::Right(path));
16872                    None
16873                }
16874            })
16875            .collect();
16876
16877        let workspace = self.workspace();
16878
16879        cx.spawn_in(window, async move |editor, cx| {
16880            let locations: Vec<Location> = future::join_all(definitions)
16881                .await
16882                .into_iter()
16883                .filter_map(|location| location.transpose())
16884                .collect::<Result<_>>()
16885                .context("location tasks")?;
16886            let mut locations = cx.update(|_, cx| {
16887                locations
16888                    .into_iter()
16889                    .map(|location| {
16890                        let buffer = location.buffer.read(cx);
16891                        (location.buffer, location.range.to_point(buffer))
16892                    })
16893                    .into_group_map()
16894            })?;
16895            let mut num_locations = 0;
16896            for ranges in locations.values_mut() {
16897                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16898                ranges.dedup();
16899                num_locations += ranges.len();
16900            }
16901
16902            if num_locations > 1 {
16903                let Some(workspace) = workspace else {
16904                    return Ok(Navigated::No);
16905                };
16906
16907                let tab_kind = match kind {
16908                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16909                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16910                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16911                    Some(GotoDefinitionKind::Type) => "Types",
16912                };
16913                let title = editor
16914                    .update_in(cx, |_, _, cx| {
16915                        let target = locations
16916                            .iter()
16917                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16918                            .map(|(buffer, location)| {
16919                                buffer
16920                                    .read(cx)
16921                                    .text_for_range(location.clone())
16922                                    .collect::<String>()
16923                            })
16924                            .filter(|text| !text.contains('\n'))
16925                            .unique()
16926                            .take(3)
16927                            .join(", ");
16928                        if target.is_empty() {
16929                            tab_kind.to_owned()
16930                        } else {
16931                            format!("{tab_kind} for {target}")
16932                        }
16933                    })
16934                    .context("buffer title")?;
16935
16936                let opened = workspace
16937                    .update_in(cx, |workspace, window, cx| {
16938                        Self::open_locations_in_multibuffer(
16939                            workspace,
16940                            locations,
16941                            title,
16942                            split,
16943                            MultibufferSelectionMode::First,
16944                            window,
16945                            cx,
16946                        )
16947                    })
16948                    .is_ok();
16949
16950                anyhow::Ok(Navigated::from_bool(opened))
16951            } else if num_locations == 0 {
16952                // If there is one url or file, open it directly
16953                match first_url_or_file {
16954                    Some(Either::Left(url)) => {
16955                        cx.update(|_, cx| cx.open_url(&url))?;
16956                        Ok(Navigated::Yes)
16957                    }
16958                    Some(Either::Right(path)) => {
16959                        let Some(workspace) = workspace else {
16960                            return Ok(Navigated::No);
16961                        };
16962
16963                        workspace
16964                            .update_in(cx, |workspace, window, cx| {
16965                                workspace.open_resolved_path(path, window, cx)
16966                            })?
16967                            .await?;
16968                        Ok(Navigated::Yes)
16969                    }
16970                    None => Ok(Navigated::No),
16971                }
16972            } else {
16973                let Some(workspace) = workspace else {
16974                    return Ok(Navigated::No);
16975                };
16976
16977                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16978                let target_range = target_ranges.first().unwrap().clone();
16979
16980                editor.update_in(cx, |editor, window, cx| {
16981                    let range = target_range.to_point(target_buffer.read(cx));
16982                    let range = editor.range_for_match(&range);
16983                    let range = collapse_multiline_range(range);
16984
16985                    if !split
16986                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16987                    {
16988                        editor.go_to_singleton_buffer_range(range, window, cx);
16989                    } else {
16990                        let pane = workspace.read(cx).active_pane().clone();
16991                        window.defer(cx, move |window, cx| {
16992                            let target_editor: Entity<Self> =
16993                                workspace.update(cx, |workspace, cx| {
16994                                    let pane = if split {
16995                                        workspace.adjacent_pane(window, cx)
16996                                    } else {
16997                                        workspace.active_pane().clone()
16998                                    };
16999
17000                                    workspace.open_project_item(
17001                                        pane,
17002                                        target_buffer.clone(),
17003                                        true,
17004                                        true,
17005                                        window,
17006                                        cx,
17007                                    )
17008                                });
17009                            target_editor.update(cx, |target_editor, cx| {
17010                                // When selecting a definition in a different buffer, disable the nav history
17011                                // to avoid creating a history entry at the previous cursor location.
17012                                pane.update(cx, |pane, _| pane.disable_history());
17013                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17014                                pane.update(cx, |pane, _| pane.enable_history());
17015                            });
17016                        });
17017                    }
17018                    Navigated::Yes
17019                })
17020            }
17021        })
17022    }
17023
17024    fn compute_target_location(
17025        &self,
17026        lsp_location: lsp::Location,
17027        server_id: LanguageServerId,
17028        window: &mut Window,
17029        cx: &mut Context<Self>,
17030    ) -> Task<anyhow::Result<Option<Location>>> {
17031        let Some(project) = self.project.clone() else {
17032            return Task::ready(Ok(None));
17033        };
17034
17035        cx.spawn_in(window, async move |editor, cx| {
17036            let location_task = editor.update(cx, |_, cx| {
17037                project.update(cx, |project, cx| {
17038                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17039                })
17040            })?;
17041            let location = Some({
17042                let target_buffer_handle = location_task.await.context("open local buffer")?;
17043                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17044                    let target_start = target_buffer
17045                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17046                    let target_end = target_buffer
17047                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17048                    target_buffer.anchor_after(target_start)
17049                        ..target_buffer.anchor_before(target_end)
17050                })?;
17051                Location {
17052                    buffer: target_buffer_handle,
17053                    range,
17054                }
17055            });
17056            Ok(location)
17057        })
17058    }
17059
17060    fn go_to_next_reference(
17061        &mut self,
17062        _: &GoToNextReference,
17063        window: &mut Window,
17064        cx: &mut Context<Self>,
17065    ) {
17066        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17067        if let Some(task) = task {
17068            task.detach();
17069        };
17070    }
17071
17072    fn go_to_prev_reference(
17073        &mut self,
17074        _: &GoToPreviousReference,
17075        window: &mut Window,
17076        cx: &mut Context<Self>,
17077    ) {
17078        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17079        if let Some(task) = task {
17080            task.detach();
17081        };
17082    }
17083
17084    pub fn go_to_reference_before_or_after_position(
17085        &mut self,
17086        direction: Direction,
17087        count: usize,
17088        window: &mut Window,
17089        cx: &mut Context<Self>,
17090    ) -> Option<Task<Result<()>>> {
17091        let selection = self.selections.newest_anchor();
17092        let head = selection.head();
17093
17094        let multi_buffer = self.buffer.read(cx);
17095
17096        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17097        let workspace = self.workspace()?;
17098        let project = workspace.read(cx).project().clone();
17099        let references =
17100            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17101        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17102            let Some(locations) = references.await? else {
17103                return Ok(());
17104            };
17105
17106            if locations.is_empty() {
17107                // totally normal - the cursor may be on something which is not
17108                // a symbol (e.g. a keyword)
17109                log::info!("no references found under cursor");
17110                return Ok(());
17111            }
17112
17113            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17114
17115            let (locations, current_location_index) =
17116                multi_buffer.update(cx, |multi_buffer, cx| {
17117                    let mut locations = locations
17118                        .into_iter()
17119                        .filter_map(|loc| {
17120                            let start = multi_buffer.buffer_anchor_to_anchor(
17121                                &loc.buffer,
17122                                loc.range.start,
17123                                cx,
17124                            )?;
17125                            let end = multi_buffer.buffer_anchor_to_anchor(
17126                                &loc.buffer,
17127                                loc.range.end,
17128                                cx,
17129                            )?;
17130                            Some(start..end)
17131                        })
17132                        .collect::<Vec<_>>();
17133
17134                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17135                    // There is an O(n) implementation, but given this list will be
17136                    // small (usually <100 items), the extra O(log(n)) factor isn't
17137                    // worth the (surprisingly large amount of) extra complexity.
17138                    locations
17139                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17140
17141                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17142
17143                    let current_location_index = locations.iter().position(|loc| {
17144                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17145                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17146                    });
17147
17148                    (locations, current_location_index)
17149                })?;
17150
17151            let Some(current_location_index) = current_location_index else {
17152                // This indicates something has gone wrong, because we already
17153                // handle the "no references" case above
17154                log::error!(
17155                    "failed to find current reference under cursor. Total references: {}",
17156                    locations.len()
17157                );
17158                return Ok(());
17159            };
17160
17161            let destination_location_index = match direction {
17162                Direction::Next => (current_location_index + count) % locations.len(),
17163                Direction::Prev => {
17164                    (current_location_index + locations.len() - count % locations.len())
17165                        % locations.len()
17166                }
17167            };
17168
17169            // TODO(cameron): is this needed?
17170            // the thinking is to avoid "jumping to the current location" (avoid
17171            // polluting "jumplist" in vim terms)
17172            if current_location_index == destination_location_index {
17173                return Ok(());
17174            }
17175
17176            let Range { start, end } = locations[destination_location_index];
17177
17178            editor.update_in(cx, |editor, window, cx| {
17179                let effects = SelectionEffects::default();
17180
17181                editor.unfold_ranges(&[start..end], false, false, cx);
17182                editor.change_selections(effects, window, cx, |s| {
17183                    s.select_ranges([start..start]);
17184                });
17185            })?;
17186
17187            Ok(())
17188        }))
17189    }
17190
17191    pub fn find_all_references(
17192        &mut self,
17193        _: &FindAllReferences,
17194        window: &mut Window,
17195        cx: &mut Context<Self>,
17196    ) -> Option<Task<Result<Navigated>>> {
17197        let selection = self
17198            .selections
17199            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17200        let multi_buffer = self.buffer.read(cx);
17201        let head = selection.head();
17202
17203        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17204        let head_anchor = multi_buffer_snapshot.anchor_at(
17205            head,
17206            if head < selection.tail() {
17207                Bias::Right
17208            } else {
17209                Bias::Left
17210            },
17211        );
17212
17213        match self
17214            .find_all_references_task_sources
17215            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17216        {
17217            Ok(_) => {
17218                log::info!(
17219                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17220                );
17221                return None;
17222            }
17223            Err(i) => {
17224                self.find_all_references_task_sources.insert(i, head_anchor);
17225            }
17226        }
17227
17228        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17229        let workspace = self.workspace()?;
17230        let project = workspace.read(cx).project().clone();
17231        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17232        Some(cx.spawn_in(window, async move |editor, cx| {
17233            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17234                if let Ok(i) = editor
17235                    .find_all_references_task_sources
17236                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17237                {
17238                    editor.find_all_references_task_sources.remove(i);
17239                }
17240            });
17241
17242            let Some(locations) = references.await? else {
17243                return anyhow::Ok(Navigated::No);
17244            };
17245            let mut locations = cx.update(|_, cx| {
17246                locations
17247                    .into_iter()
17248                    .map(|location| {
17249                        let buffer = location.buffer.read(cx);
17250                        (location.buffer, location.range.to_point(buffer))
17251                    })
17252                    .into_group_map()
17253            })?;
17254            if locations.is_empty() {
17255                return anyhow::Ok(Navigated::No);
17256            }
17257            for ranges in locations.values_mut() {
17258                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17259                ranges.dedup();
17260            }
17261
17262            workspace.update_in(cx, |workspace, window, cx| {
17263                let target = locations
17264                    .iter()
17265                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17266                    .map(|(buffer, location)| {
17267                        buffer
17268                            .read(cx)
17269                            .text_for_range(location.clone())
17270                            .collect::<String>()
17271                    })
17272                    .filter(|text| !text.contains('\n'))
17273                    .unique()
17274                    .take(3)
17275                    .join(", ");
17276                let title = if target.is_empty() {
17277                    "References".to_owned()
17278                } else {
17279                    format!("References to {target}")
17280                };
17281                Self::open_locations_in_multibuffer(
17282                    workspace,
17283                    locations,
17284                    title,
17285                    false,
17286                    MultibufferSelectionMode::First,
17287                    window,
17288                    cx,
17289                );
17290                Navigated::Yes
17291            })
17292        }))
17293    }
17294
17295    /// Opens a multibuffer with the given project locations in it
17296    pub fn open_locations_in_multibuffer(
17297        workspace: &mut Workspace,
17298        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17299        title: String,
17300        split: bool,
17301        multibuffer_selection_mode: MultibufferSelectionMode,
17302        window: &mut Window,
17303        cx: &mut Context<Workspace>,
17304    ) {
17305        if locations.is_empty() {
17306            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17307            return;
17308        }
17309
17310        let capability = workspace.project().read(cx).capability();
17311        let mut ranges = <Vec<Range<Anchor>>>::new();
17312
17313        // a key to find existing multibuffer editors with the same set of locations
17314        // to prevent us from opening more and more multibuffer tabs for searches and the like
17315        let mut key = (title.clone(), vec![]);
17316        let excerpt_buffer = cx.new(|cx| {
17317            let key = &mut key.1;
17318            let mut multibuffer = MultiBuffer::new(capability);
17319            for (buffer, mut ranges_for_buffer) in locations {
17320                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17321                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17322                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17323                    PathKey::for_buffer(&buffer, cx),
17324                    buffer.clone(),
17325                    ranges_for_buffer,
17326                    multibuffer_context_lines(cx),
17327                    cx,
17328                );
17329                ranges.extend(new_ranges)
17330            }
17331
17332            multibuffer.with_title(title)
17333        });
17334        let existing = workspace.active_pane().update(cx, |pane, cx| {
17335            pane.items()
17336                .filter_map(|item| item.downcast::<Editor>())
17337                .find(|editor| {
17338                    editor
17339                        .read(cx)
17340                        .lookup_key
17341                        .as_ref()
17342                        .and_then(|it| {
17343                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17344                        })
17345                        .is_some_and(|it| *it == key)
17346                })
17347        });
17348        let editor = existing.unwrap_or_else(|| {
17349            cx.new(|cx| {
17350                let mut editor = Editor::for_multibuffer(
17351                    excerpt_buffer,
17352                    Some(workspace.project().clone()),
17353                    window,
17354                    cx,
17355                );
17356                editor.lookup_key = Some(Box::new(key));
17357                editor
17358            })
17359        });
17360        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17361            MultibufferSelectionMode::First => {
17362                if let Some(first_range) = ranges.first() {
17363                    editor.change_selections(
17364                        SelectionEffects::no_scroll(),
17365                        window,
17366                        cx,
17367                        |selections| {
17368                            selections.clear_disjoint();
17369                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17370                        },
17371                    );
17372                }
17373                editor.highlight_background::<Self>(
17374                    &ranges,
17375                    |theme| theme.colors().editor_highlighted_line_background,
17376                    cx,
17377                );
17378            }
17379            MultibufferSelectionMode::All => {
17380                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17381                    selections.clear_disjoint();
17382                    selections.select_anchor_ranges(ranges);
17383                });
17384            }
17385        });
17386
17387        let item = Box::new(editor);
17388        let item_id = item.item_id();
17389
17390        if split {
17391            let pane = workspace.adjacent_pane(window, cx);
17392            workspace.add_item(pane, item, None, true, true, window, cx);
17393        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17394            let (preview_item_id, preview_item_idx) =
17395                workspace.active_pane().read_with(cx, |pane, _| {
17396                    (pane.preview_item_id(), pane.preview_item_idx())
17397                });
17398
17399            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17400
17401            if let Some(preview_item_id) = preview_item_id {
17402                workspace.active_pane().update(cx, |pane, cx| {
17403                    pane.remove_item(preview_item_id, false, false, window, cx);
17404                });
17405            }
17406        } else {
17407            workspace.add_item_to_active_pane(item, None, true, window, cx);
17408        }
17409        workspace.active_pane().update(cx, |pane, cx| {
17410            pane.set_preview_item_id(Some(item_id), cx);
17411        });
17412    }
17413
17414    pub fn rename(
17415        &mut self,
17416        _: &Rename,
17417        window: &mut Window,
17418        cx: &mut Context<Self>,
17419    ) -> Option<Task<Result<()>>> {
17420        use language::ToOffset as _;
17421
17422        let provider = self.semantics_provider.clone()?;
17423        let selection = self.selections.newest_anchor().clone();
17424        let (cursor_buffer, cursor_buffer_position) = self
17425            .buffer
17426            .read(cx)
17427            .text_anchor_for_position(selection.head(), cx)?;
17428        let (tail_buffer, cursor_buffer_position_end) = self
17429            .buffer
17430            .read(cx)
17431            .text_anchor_for_position(selection.tail(), cx)?;
17432        if tail_buffer != cursor_buffer {
17433            return None;
17434        }
17435
17436        let snapshot = cursor_buffer.read(cx).snapshot();
17437        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17438        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17439        let prepare_rename = provider
17440            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17441            .unwrap_or_else(|| Task::ready(Ok(None)));
17442        drop(snapshot);
17443
17444        Some(cx.spawn_in(window, async move |this, cx| {
17445            let rename_range = if let Some(range) = prepare_rename.await? {
17446                Some(range)
17447            } else {
17448                this.update(cx, |this, cx| {
17449                    let buffer = this.buffer.read(cx).snapshot(cx);
17450                    let mut buffer_highlights = this
17451                        .document_highlights_for_position(selection.head(), &buffer)
17452                        .filter(|highlight| {
17453                            highlight.start.excerpt_id == selection.head().excerpt_id
17454                                && highlight.end.excerpt_id == selection.head().excerpt_id
17455                        });
17456                    buffer_highlights
17457                        .next()
17458                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17459                })?
17460            };
17461            if let Some(rename_range) = rename_range {
17462                this.update_in(cx, |this, window, cx| {
17463                    let snapshot = cursor_buffer.read(cx).snapshot();
17464                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17465                    let cursor_offset_in_rename_range =
17466                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17467                    let cursor_offset_in_rename_range_end =
17468                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17469
17470                    this.take_rename(false, window, cx);
17471                    let buffer = this.buffer.read(cx).read(cx);
17472                    let cursor_offset = selection.head().to_offset(&buffer);
17473                    let rename_start =
17474                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17475                    let rename_end = rename_start + rename_buffer_range.len();
17476                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17477                    let mut old_highlight_id = None;
17478                    let old_name: Arc<str> = buffer
17479                        .chunks(rename_start..rename_end, true)
17480                        .map(|chunk| {
17481                            if old_highlight_id.is_none() {
17482                                old_highlight_id = chunk.syntax_highlight_id;
17483                            }
17484                            chunk.text
17485                        })
17486                        .collect::<String>()
17487                        .into();
17488
17489                    drop(buffer);
17490
17491                    // Position the selection in the rename editor so that it matches the current selection.
17492                    this.show_local_selections = false;
17493                    let rename_editor = cx.new(|cx| {
17494                        let mut editor = Editor::single_line(window, cx);
17495                        editor.buffer.update(cx, |buffer, cx| {
17496                            buffer.edit(
17497                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
17498                                None,
17499                                cx,
17500                            )
17501                        });
17502                        let cursor_offset_in_rename_range =
17503                            MultiBufferOffset(cursor_offset_in_rename_range);
17504                        let cursor_offset_in_rename_range_end =
17505                            MultiBufferOffset(cursor_offset_in_rename_range_end);
17506                        let rename_selection_range = match cursor_offset_in_rename_range
17507                            .cmp(&cursor_offset_in_rename_range_end)
17508                        {
17509                            Ordering::Equal => {
17510                                editor.select_all(&SelectAll, window, cx);
17511                                return editor;
17512                            }
17513                            Ordering::Less => {
17514                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17515                            }
17516                            Ordering::Greater => {
17517                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17518                            }
17519                        };
17520                        if rename_selection_range.end.0 > old_name.len() {
17521                            editor.select_all(&SelectAll, window, cx);
17522                        } else {
17523                            editor.change_selections(Default::default(), window, cx, |s| {
17524                                s.select_ranges([rename_selection_range]);
17525                            });
17526                        }
17527                        editor
17528                    });
17529                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17530                        if e == &EditorEvent::Focused {
17531                            cx.emit(EditorEvent::FocusedIn)
17532                        }
17533                    })
17534                    .detach();
17535
17536                    let write_highlights =
17537                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17538                    let read_highlights =
17539                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17540                    let ranges = write_highlights
17541                        .iter()
17542                        .flat_map(|(_, ranges)| ranges.iter())
17543                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17544                        .cloned()
17545                        .collect();
17546
17547                    this.highlight_text::<Rename>(
17548                        ranges,
17549                        HighlightStyle {
17550                            fade_out: Some(0.6),
17551                            ..Default::default()
17552                        },
17553                        cx,
17554                    );
17555                    let rename_focus_handle = rename_editor.focus_handle(cx);
17556                    window.focus(&rename_focus_handle);
17557                    let block_id = this.insert_blocks(
17558                        [BlockProperties {
17559                            style: BlockStyle::Flex,
17560                            placement: BlockPlacement::Below(range.start),
17561                            height: Some(1),
17562                            render: Arc::new({
17563                                let rename_editor = rename_editor.clone();
17564                                move |cx: &mut BlockContext| {
17565                                    let mut text_style = cx.editor_style.text.clone();
17566                                    if let Some(highlight_style) = old_highlight_id
17567                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17568                                    {
17569                                        text_style = text_style.highlight(highlight_style);
17570                                    }
17571                                    div()
17572                                        .block_mouse_except_scroll()
17573                                        .pl(cx.anchor_x)
17574                                        .child(EditorElement::new(
17575                                            &rename_editor,
17576                                            EditorStyle {
17577                                                background: cx.theme().system().transparent,
17578                                                local_player: cx.editor_style.local_player,
17579                                                text: text_style,
17580                                                scrollbar_width: cx.editor_style.scrollbar_width,
17581                                                syntax: cx.editor_style.syntax.clone(),
17582                                                status: cx.editor_style.status.clone(),
17583                                                inlay_hints_style: HighlightStyle {
17584                                                    font_weight: Some(FontWeight::BOLD),
17585                                                    ..make_inlay_hints_style(cx.app)
17586                                                },
17587                                                edit_prediction_styles: make_suggestion_styles(
17588                                                    cx.app,
17589                                                ),
17590                                                ..EditorStyle::default()
17591                                            },
17592                                        ))
17593                                        .into_any_element()
17594                                }
17595                            }),
17596                            priority: 0,
17597                        }],
17598                        Some(Autoscroll::fit()),
17599                        cx,
17600                    )[0];
17601                    this.pending_rename = Some(RenameState {
17602                        range,
17603                        old_name,
17604                        editor: rename_editor,
17605                        block_id,
17606                    });
17607                })?;
17608            }
17609
17610            Ok(())
17611        }))
17612    }
17613
17614    pub fn confirm_rename(
17615        &mut self,
17616        _: &ConfirmRename,
17617        window: &mut Window,
17618        cx: &mut Context<Self>,
17619    ) -> Option<Task<Result<()>>> {
17620        let rename = self.take_rename(false, window, cx)?;
17621        let workspace = self.workspace()?.downgrade();
17622        let (buffer, start) = self
17623            .buffer
17624            .read(cx)
17625            .text_anchor_for_position(rename.range.start, cx)?;
17626        let (end_buffer, _) = self
17627            .buffer
17628            .read(cx)
17629            .text_anchor_for_position(rename.range.end, cx)?;
17630        if buffer != end_buffer {
17631            return None;
17632        }
17633
17634        let old_name = rename.old_name;
17635        let new_name = rename.editor.read(cx).text(cx);
17636
17637        let rename = self.semantics_provider.as_ref()?.perform_rename(
17638            &buffer,
17639            start,
17640            new_name.clone(),
17641            cx,
17642        )?;
17643
17644        Some(cx.spawn_in(window, async move |editor, cx| {
17645            let project_transaction = rename.await?;
17646            Self::open_project_transaction(
17647                &editor,
17648                workspace,
17649                project_transaction,
17650                format!("Rename: {}{}", old_name, new_name),
17651                cx,
17652            )
17653            .await?;
17654
17655            editor.update(cx, |editor, cx| {
17656                editor.refresh_document_highlights(cx);
17657            })?;
17658            Ok(())
17659        }))
17660    }
17661
17662    fn take_rename(
17663        &mut self,
17664        moving_cursor: bool,
17665        window: &mut Window,
17666        cx: &mut Context<Self>,
17667    ) -> Option<RenameState> {
17668        let rename = self.pending_rename.take()?;
17669        if rename.editor.focus_handle(cx).is_focused(window) {
17670            window.focus(&self.focus_handle);
17671        }
17672
17673        self.remove_blocks(
17674            [rename.block_id].into_iter().collect(),
17675            Some(Autoscroll::fit()),
17676            cx,
17677        );
17678        self.clear_highlights::<Rename>(cx);
17679        self.show_local_selections = true;
17680
17681        if moving_cursor {
17682            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17683                editor
17684                    .selections
17685                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
17686                    .head()
17687            });
17688
17689            // Update the selection to match the position of the selection inside
17690            // the rename editor.
17691            let snapshot = self.buffer.read(cx).read(cx);
17692            let rename_range = rename.range.to_offset(&snapshot);
17693            let cursor_in_editor = snapshot
17694                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17695                .min(rename_range.end);
17696            drop(snapshot);
17697
17698            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17699                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17700            });
17701        } else {
17702            self.refresh_document_highlights(cx);
17703        }
17704
17705        Some(rename)
17706    }
17707
17708    pub fn pending_rename(&self) -> Option<&RenameState> {
17709        self.pending_rename.as_ref()
17710    }
17711
17712    fn format(
17713        &mut self,
17714        _: &Format,
17715        window: &mut Window,
17716        cx: &mut Context<Self>,
17717    ) -> Option<Task<Result<()>>> {
17718        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17719
17720        let project = match &self.project {
17721            Some(project) => project.clone(),
17722            None => return None,
17723        };
17724
17725        Some(self.perform_format(
17726            project,
17727            FormatTrigger::Manual,
17728            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17729            window,
17730            cx,
17731        ))
17732    }
17733
17734    fn format_selections(
17735        &mut self,
17736        _: &FormatSelections,
17737        window: &mut Window,
17738        cx: &mut Context<Self>,
17739    ) -> Option<Task<Result<()>>> {
17740        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17741
17742        let project = match &self.project {
17743            Some(project) => project.clone(),
17744            None => return None,
17745        };
17746
17747        let ranges = self
17748            .selections
17749            .all_adjusted(&self.display_snapshot(cx))
17750            .into_iter()
17751            .map(|selection| selection.range())
17752            .collect_vec();
17753
17754        Some(self.perform_format(
17755            project,
17756            FormatTrigger::Manual,
17757            FormatTarget::Ranges(ranges),
17758            window,
17759            cx,
17760        ))
17761    }
17762
17763    fn perform_format(
17764        &mut self,
17765        project: Entity<Project>,
17766        trigger: FormatTrigger,
17767        target: FormatTarget,
17768        window: &mut Window,
17769        cx: &mut Context<Self>,
17770    ) -> Task<Result<()>> {
17771        let buffer = self.buffer.clone();
17772        let (buffers, target) = match target {
17773            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17774            FormatTarget::Ranges(selection_ranges) => {
17775                let multi_buffer = buffer.read(cx);
17776                let snapshot = multi_buffer.read(cx);
17777                let mut buffers = HashSet::default();
17778                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17779                    BTreeMap::new();
17780                for selection_range in selection_ranges {
17781                    for (buffer, buffer_range, _) in
17782                        snapshot.range_to_buffer_ranges(selection_range)
17783                    {
17784                        let buffer_id = buffer.remote_id();
17785                        let start = buffer.anchor_before(buffer_range.start);
17786                        let end = buffer.anchor_after(buffer_range.end);
17787                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17788                        buffer_id_to_ranges
17789                            .entry(buffer_id)
17790                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17791                            .or_insert_with(|| vec![start..end]);
17792                    }
17793                }
17794                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17795            }
17796        };
17797
17798        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17799        let selections_prev = transaction_id_prev
17800            .and_then(|transaction_id_prev| {
17801                // default to selections as they were after the last edit, if we have them,
17802                // instead of how they are now.
17803                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17804                // will take you back to where you made the last edit, instead of staying where you scrolled
17805                self.selection_history
17806                    .transaction(transaction_id_prev)
17807                    .map(|t| t.0.clone())
17808            })
17809            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17810
17811        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17812        let format = project.update(cx, |project, cx| {
17813            project.format(buffers, target, true, trigger, cx)
17814        });
17815
17816        cx.spawn_in(window, async move |editor, cx| {
17817            let transaction = futures::select_biased! {
17818                transaction = format.log_err().fuse() => transaction,
17819                () = timeout => {
17820                    log::warn!("timed out waiting for formatting");
17821                    None
17822                }
17823            };
17824
17825            buffer
17826                .update(cx, |buffer, cx| {
17827                    if let Some(transaction) = transaction
17828                        && !buffer.is_singleton()
17829                    {
17830                        buffer.push_transaction(&transaction.0, cx);
17831                    }
17832                    cx.notify();
17833                })
17834                .ok();
17835
17836            if let Some(transaction_id_now) =
17837                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17838            {
17839                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17840                if has_new_transaction {
17841                    _ = editor.update(cx, |editor, _| {
17842                        editor
17843                            .selection_history
17844                            .insert_transaction(transaction_id_now, selections_prev);
17845                    });
17846                }
17847            }
17848
17849            Ok(())
17850        })
17851    }
17852
17853    fn organize_imports(
17854        &mut self,
17855        _: &OrganizeImports,
17856        window: &mut Window,
17857        cx: &mut Context<Self>,
17858    ) -> Option<Task<Result<()>>> {
17859        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17860        let project = match &self.project {
17861            Some(project) => project.clone(),
17862            None => return None,
17863        };
17864        Some(self.perform_code_action_kind(
17865            project,
17866            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17867            window,
17868            cx,
17869        ))
17870    }
17871
17872    fn perform_code_action_kind(
17873        &mut self,
17874        project: Entity<Project>,
17875        kind: CodeActionKind,
17876        window: &mut Window,
17877        cx: &mut Context<Self>,
17878    ) -> Task<Result<()>> {
17879        let buffer = self.buffer.clone();
17880        let buffers = buffer.read(cx).all_buffers();
17881        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17882        let apply_action = project.update(cx, |project, cx| {
17883            project.apply_code_action_kind(buffers, kind, true, cx)
17884        });
17885        cx.spawn_in(window, async move |_, cx| {
17886            let transaction = futures::select_biased! {
17887                () = timeout => {
17888                    log::warn!("timed out waiting for executing code action");
17889                    None
17890                }
17891                transaction = apply_action.log_err().fuse() => transaction,
17892            };
17893            buffer
17894                .update(cx, |buffer, cx| {
17895                    // check if we need this
17896                    if let Some(transaction) = transaction
17897                        && !buffer.is_singleton()
17898                    {
17899                        buffer.push_transaction(&transaction.0, cx);
17900                    }
17901                    cx.notify();
17902                })
17903                .ok();
17904            Ok(())
17905        })
17906    }
17907
17908    pub fn restart_language_server(
17909        &mut self,
17910        _: &RestartLanguageServer,
17911        _: &mut Window,
17912        cx: &mut Context<Self>,
17913    ) {
17914        if let Some(project) = self.project.clone() {
17915            self.buffer.update(cx, |multi_buffer, cx| {
17916                project.update(cx, |project, cx| {
17917                    project.restart_language_servers_for_buffers(
17918                        multi_buffer.all_buffers().into_iter().collect(),
17919                        HashSet::default(),
17920                        cx,
17921                    );
17922                });
17923            })
17924        }
17925    }
17926
17927    pub fn stop_language_server(
17928        &mut self,
17929        _: &StopLanguageServer,
17930        _: &mut Window,
17931        cx: &mut Context<Self>,
17932    ) {
17933        if let Some(project) = self.project.clone() {
17934            self.buffer.update(cx, |multi_buffer, cx| {
17935                project.update(cx, |project, cx| {
17936                    project.stop_language_servers_for_buffers(
17937                        multi_buffer.all_buffers().into_iter().collect(),
17938                        HashSet::default(),
17939                        cx,
17940                    );
17941                });
17942            });
17943            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17944        }
17945    }
17946
17947    fn cancel_language_server_work(
17948        workspace: &mut Workspace,
17949        _: &actions::CancelLanguageServerWork,
17950        _: &mut Window,
17951        cx: &mut Context<Workspace>,
17952    ) {
17953        let project = workspace.project();
17954        let buffers = workspace
17955            .active_item(cx)
17956            .and_then(|item| item.act_as::<Editor>(cx))
17957            .map_or(HashSet::default(), |editor| {
17958                editor.read(cx).buffer.read(cx).all_buffers()
17959            });
17960        project.update(cx, |project, cx| {
17961            project.cancel_language_server_work_for_buffers(buffers, cx);
17962        });
17963    }
17964
17965    fn show_character_palette(
17966        &mut self,
17967        _: &ShowCharacterPalette,
17968        window: &mut Window,
17969        _: &mut Context<Self>,
17970    ) {
17971        window.show_character_palette();
17972    }
17973
17974    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17975        if !self.diagnostics_enabled() {
17976            return;
17977        }
17978
17979        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17980            let buffer = self.buffer.read(cx).snapshot(cx);
17981            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17982            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17983            let is_valid = buffer
17984                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
17985                .any(|entry| {
17986                    entry.diagnostic.is_primary
17987                        && !entry.range.is_empty()
17988                        && entry.range.start == primary_range_start
17989                        && entry.diagnostic.message == active_diagnostics.active_message
17990                });
17991
17992            if !is_valid {
17993                self.dismiss_diagnostics(cx);
17994            }
17995        }
17996    }
17997
17998    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17999        match &self.active_diagnostics {
18000            ActiveDiagnostic::Group(group) => Some(group),
18001            _ => None,
18002        }
18003    }
18004
18005    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18006        if !self.diagnostics_enabled() {
18007            return;
18008        }
18009        self.dismiss_diagnostics(cx);
18010        self.active_diagnostics = ActiveDiagnostic::All;
18011    }
18012
18013    fn activate_diagnostics(
18014        &mut self,
18015        buffer_id: BufferId,
18016        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18017        window: &mut Window,
18018        cx: &mut Context<Self>,
18019    ) {
18020        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18021            return;
18022        }
18023        self.dismiss_diagnostics(cx);
18024        let snapshot = self.snapshot(window, cx);
18025        let buffer = self.buffer.read(cx).snapshot(cx);
18026        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18027            return;
18028        };
18029
18030        let diagnostic_group = buffer
18031            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18032            .collect::<Vec<_>>();
18033
18034        let language_registry = self
18035            .project()
18036            .map(|project| project.read(cx).languages().clone());
18037
18038        let blocks = renderer.render_group(
18039            diagnostic_group,
18040            buffer_id,
18041            snapshot,
18042            cx.weak_entity(),
18043            language_registry,
18044            cx,
18045        );
18046
18047        let blocks = self.display_map.update(cx, |display_map, cx| {
18048            display_map.insert_blocks(blocks, cx).into_iter().collect()
18049        });
18050        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18051            active_range: buffer.anchor_before(diagnostic.range.start)
18052                ..buffer.anchor_after(diagnostic.range.end),
18053            active_message: diagnostic.diagnostic.message.clone(),
18054            group_id: diagnostic.diagnostic.group_id,
18055            blocks,
18056        });
18057        cx.notify();
18058    }
18059
18060    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18061        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18062            return;
18063        };
18064
18065        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18066        if let ActiveDiagnostic::Group(group) = prev {
18067            self.display_map.update(cx, |display_map, cx| {
18068                display_map.remove_blocks(group.blocks, cx);
18069            });
18070            cx.notify();
18071        }
18072    }
18073
18074    /// Disable inline diagnostics rendering for this editor.
18075    pub fn disable_inline_diagnostics(&mut self) {
18076        self.inline_diagnostics_enabled = false;
18077        self.inline_diagnostics_update = Task::ready(());
18078        self.inline_diagnostics.clear();
18079    }
18080
18081    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18082        self.diagnostics_enabled = false;
18083        self.dismiss_diagnostics(cx);
18084        self.inline_diagnostics_update = Task::ready(());
18085        self.inline_diagnostics.clear();
18086    }
18087
18088    pub fn disable_word_completions(&mut self) {
18089        self.word_completions_enabled = false;
18090    }
18091
18092    pub fn diagnostics_enabled(&self) -> bool {
18093        self.diagnostics_enabled && self.mode.is_full()
18094    }
18095
18096    pub fn inline_diagnostics_enabled(&self) -> bool {
18097        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18098    }
18099
18100    pub fn show_inline_diagnostics(&self) -> bool {
18101        self.show_inline_diagnostics
18102    }
18103
18104    pub fn toggle_inline_diagnostics(
18105        &mut self,
18106        _: &ToggleInlineDiagnostics,
18107        window: &mut Window,
18108        cx: &mut Context<Editor>,
18109    ) {
18110        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18111        self.refresh_inline_diagnostics(false, window, cx);
18112    }
18113
18114    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18115        self.diagnostics_max_severity = severity;
18116        self.display_map.update(cx, |display_map, _| {
18117            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18118        });
18119    }
18120
18121    pub fn toggle_diagnostics(
18122        &mut self,
18123        _: &ToggleDiagnostics,
18124        window: &mut Window,
18125        cx: &mut Context<Editor>,
18126    ) {
18127        if !self.diagnostics_enabled() {
18128            return;
18129        }
18130
18131        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18132            EditorSettings::get_global(cx)
18133                .diagnostics_max_severity
18134                .filter(|severity| severity != &DiagnosticSeverity::Off)
18135                .unwrap_or(DiagnosticSeverity::Hint)
18136        } else {
18137            DiagnosticSeverity::Off
18138        };
18139        self.set_max_diagnostics_severity(new_severity, cx);
18140        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18141            self.active_diagnostics = ActiveDiagnostic::None;
18142            self.inline_diagnostics_update = Task::ready(());
18143            self.inline_diagnostics.clear();
18144        } else {
18145            self.refresh_inline_diagnostics(false, window, cx);
18146        }
18147
18148        cx.notify();
18149    }
18150
18151    pub fn toggle_minimap(
18152        &mut self,
18153        _: &ToggleMinimap,
18154        window: &mut Window,
18155        cx: &mut Context<Editor>,
18156    ) {
18157        if self.supports_minimap(cx) {
18158            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18159        }
18160    }
18161
18162    fn refresh_inline_diagnostics(
18163        &mut self,
18164        debounce: bool,
18165        window: &mut Window,
18166        cx: &mut Context<Self>,
18167    ) {
18168        let max_severity = ProjectSettings::get_global(cx)
18169            .diagnostics
18170            .inline
18171            .max_severity
18172            .unwrap_or(self.diagnostics_max_severity);
18173
18174        if !self.inline_diagnostics_enabled()
18175            || !self.diagnostics_enabled()
18176            || !self.show_inline_diagnostics
18177            || max_severity == DiagnosticSeverity::Off
18178        {
18179            self.inline_diagnostics_update = Task::ready(());
18180            self.inline_diagnostics.clear();
18181            return;
18182        }
18183
18184        let debounce_ms = ProjectSettings::get_global(cx)
18185            .diagnostics
18186            .inline
18187            .update_debounce_ms;
18188        let debounce = if debounce && debounce_ms > 0 {
18189            Some(Duration::from_millis(debounce_ms))
18190        } else {
18191            None
18192        };
18193        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18194            if let Some(debounce) = debounce {
18195                cx.background_executor().timer(debounce).await;
18196            }
18197            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18198                editor
18199                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18200                    .ok()
18201            }) else {
18202                return;
18203            };
18204
18205            let new_inline_diagnostics = cx
18206                .background_spawn(async move {
18207                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18208                    for diagnostic_entry in
18209                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18210                    {
18211                        let message = diagnostic_entry
18212                            .diagnostic
18213                            .message
18214                            .split_once('\n')
18215                            .map(|(line, _)| line)
18216                            .map(SharedString::new)
18217                            .unwrap_or_else(|| {
18218                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18219                            });
18220                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18221                        let (Ok(i) | Err(i)) = inline_diagnostics
18222                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18223                        inline_diagnostics.insert(
18224                            i,
18225                            (
18226                                start_anchor,
18227                                InlineDiagnostic {
18228                                    message,
18229                                    group_id: diagnostic_entry.diagnostic.group_id,
18230                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18231                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18232                                    severity: diagnostic_entry.diagnostic.severity,
18233                                },
18234                            ),
18235                        );
18236                    }
18237                    inline_diagnostics
18238                })
18239                .await;
18240
18241            editor
18242                .update(cx, |editor, cx| {
18243                    editor.inline_diagnostics = new_inline_diagnostics;
18244                    cx.notify();
18245                })
18246                .ok();
18247        });
18248    }
18249
18250    fn pull_diagnostics(
18251        &mut self,
18252        buffer_id: Option<BufferId>,
18253        window: &Window,
18254        cx: &mut Context<Self>,
18255    ) -> Option<()> {
18256        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18257            return None;
18258        }
18259        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18260            .diagnostics
18261            .lsp_pull_diagnostics;
18262        if !pull_diagnostics_settings.enabled {
18263            return None;
18264        }
18265        let project = self.project()?.downgrade();
18266        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18267        let mut buffers = self.buffer.read(cx).all_buffers();
18268        buffers.retain(|buffer| {
18269            let buffer_id_to_retain = buffer.read(cx).remote_id();
18270            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18271                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18272        });
18273        if buffers.is_empty() {
18274            self.pull_diagnostics_task = Task::ready(());
18275            return None;
18276        }
18277
18278        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18279            cx.background_executor().timer(debounce).await;
18280
18281            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18282                buffers
18283                    .into_iter()
18284                    .filter_map(|buffer| {
18285                        project
18286                            .update(cx, |project, cx| {
18287                                project.lsp_store().update(cx, |lsp_store, cx| {
18288                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18289                                })
18290                            })
18291                            .ok()
18292                    })
18293                    .collect::<FuturesUnordered<_>>()
18294            }) else {
18295                return;
18296            };
18297
18298            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18299                match pull_task {
18300                    Ok(()) => {
18301                        if editor
18302                            .update_in(cx, |editor, window, cx| {
18303                                editor.update_diagnostics_state(window, cx);
18304                            })
18305                            .is_err()
18306                        {
18307                            return;
18308                        }
18309                    }
18310                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18311                }
18312            }
18313        });
18314
18315        Some(())
18316    }
18317
18318    pub fn set_selections_from_remote(
18319        &mut self,
18320        selections: Vec<Selection<Anchor>>,
18321        pending_selection: Option<Selection<Anchor>>,
18322        window: &mut Window,
18323        cx: &mut Context<Self>,
18324    ) {
18325        let old_cursor_position = self.selections.newest_anchor().head();
18326        self.selections
18327            .change_with(&self.display_snapshot(cx), |s| {
18328                s.select_anchors(selections);
18329                if let Some(pending_selection) = pending_selection {
18330                    s.set_pending(pending_selection, SelectMode::Character);
18331                } else {
18332                    s.clear_pending();
18333                }
18334            });
18335        self.selections_did_change(
18336            false,
18337            &old_cursor_position,
18338            SelectionEffects::default(),
18339            window,
18340            cx,
18341        );
18342    }
18343
18344    pub fn transact(
18345        &mut self,
18346        window: &mut Window,
18347        cx: &mut Context<Self>,
18348        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18349    ) -> Option<TransactionId> {
18350        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18351            this.start_transaction_at(Instant::now(), window, cx);
18352            update(this, window, cx);
18353            this.end_transaction_at(Instant::now(), cx)
18354        })
18355    }
18356
18357    pub fn start_transaction_at(
18358        &mut self,
18359        now: Instant,
18360        window: &mut Window,
18361        cx: &mut Context<Self>,
18362    ) -> Option<TransactionId> {
18363        self.end_selection(window, cx);
18364        if let Some(tx_id) = self
18365            .buffer
18366            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18367        {
18368            self.selection_history
18369                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18370            cx.emit(EditorEvent::TransactionBegun {
18371                transaction_id: tx_id,
18372            });
18373            Some(tx_id)
18374        } else {
18375            None
18376        }
18377    }
18378
18379    pub fn end_transaction_at(
18380        &mut self,
18381        now: Instant,
18382        cx: &mut Context<Self>,
18383    ) -> Option<TransactionId> {
18384        if let Some(transaction_id) = self
18385            .buffer
18386            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18387        {
18388            if let Some((_, end_selections)) =
18389                self.selection_history.transaction_mut(transaction_id)
18390            {
18391                *end_selections = Some(self.selections.disjoint_anchors_arc());
18392            } else {
18393                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18394            }
18395
18396            cx.emit(EditorEvent::Edited { transaction_id });
18397            Some(transaction_id)
18398        } else {
18399            None
18400        }
18401    }
18402
18403    pub fn modify_transaction_selection_history(
18404        &mut self,
18405        transaction_id: TransactionId,
18406        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18407    ) -> bool {
18408        self.selection_history
18409            .transaction_mut(transaction_id)
18410            .map(modify)
18411            .is_some()
18412    }
18413
18414    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18415        if self.selection_mark_mode {
18416            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18417                s.move_with(|_, sel| {
18418                    sel.collapse_to(sel.head(), SelectionGoal::None);
18419                });
18420            })
18421        }
18422        self.selection_mark_mode = true;
18423        cx.notify();
18424    }
18425
18426    pub fn swap_selection_ends(
18427        &mut self,
18428        _: &actions::SwapSelectionEnds,
18429        window: &mut Window,
18430        cx: &mut Context<Self>,
18431    ) {
18432        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18433            s.move_with(|_, sel| {
18434                if sel.start != sel.end {
18435                    sel.reversed = !sel.reversed
18436                }
18437            });
18438        });
18439        self.request_autoscroll(Autoscroll::newest(), cx);
18440        cx.notify();
18441    }
18442
18443    pub fn toggle_focus(
18444        workspace: &mut Workspace,
18445        _: &actions::ToggleFocus,
18446        window: &mut Window,
18447        cx: &mut Context<Workspace>,
18448    ) {
18449        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18450            return;
18451        };
18452        workspace.activate_item(&item, true, true, window, cx);
18453    }
18454
18455    pub fn toggle_fold(
18456        &mut self,
18457        _: &actions::ToggleFold,
18458        window: &mut Window,
18459        cx: &mut Context<Self>,
18460    ) {
18461        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18462            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18463            let selection = self.selections.newest::<Point>(&display_map);
18464
18465            let range = if selection.is_empty() {
18466                let point = selection.head().to_display_point(&display_map);
18467                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18468                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18469                    .to_point(&display_map);
18470                start..end
18471            } else {
18472                selection.range()
18473            };
18474            if display_map.folds_in_range(range).next().is_some() {
18475                self.unfold_lines(&Default::default(), window, cx)
18476            } else {
18477                self.fold(&Default::default(), window, cx)
18478            }
18479        } else {
18480            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18481            let buffer_ids: HashSet<_> = self
18482                .selections
18483                .disjoint_anchor_ranges()
18484                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18485                .collect();
18486
18487            let should_unfold = buffer_ids
18488                .iter()
18489                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18490
18491            for buffer_id in buffer_ids {
18492                if should_unfold {
18493                    self.unfold_buffer(buffer_id, cx);
18494                } else {
18495                    self.fold_buffer(buffer_id, cx);
18496                }
18497            }
18498        }
18499    }
18500
18501    pub fn toggle_fold_recursive(
18502        &mut self,
18503        _: &actions::ToggleFoldRecursive,
18504        window: &mut Window,
18505        cx: &mut Context<Self>,
18506    ) {
18507        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18508
18509        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18510        let range = if selection.is_empty() {
18511            let point = selection.head().to_display_point(&display_map);
18512            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18513            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18514                .to_point(&display_map);
18515            start..end
18516        } else {
18517            selection.range()
18518        };
18519        if display_map.folds_in_range(range).next().is_some() {
18520            self.unfold_recursive(&Default::default(), window, cx)
18521        } else {
18522            self.fold_recursive(&Default::default(), window, cx)
18523        }
18524    }
18525
18526    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18527        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18528            let mut to_fold = Vec::new();
18529            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18530            let selections = self.selections.all_adjusted(&display_map);
18531
18532            for selection in selections {
18533                let range = selection.range().sorted();
18534                let buffer_start_row = range.start.row;
18535
18536                if range.start.row != range.end.row {
18537                    let mut found = false;
18538                    let mut row = range.start.row;
18539                    while row <= range.end.row {
18540                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18541                        {
18542                            found = true;
18543                            row = crease.range().end.row + 1;
18544                            to_fold.push(crease);
18545                        } else {
18546                            row += 1
18547                        }
18548                    }
18549                    if found {
18550                        continue;
18551                    }
18552                }
18553
18554                for row in (0..=range.start.row).rev() {
18555                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18556                        && crease.range().end.row >= buffer_start_row
18557                    {
18558                        to_fold.push(crease);
18559                        if row <= range.start.row {
18560                            break;
18561                        }
18562                    }
18563                }
18564            }
18565
18566            self.fold_creases(to_fold, true, window, cx);
18567        } else {
18568            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18569            let buffer_ids = self
18570                .selections
18571                .disjoint_anchor_ranges()
18572                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18573                .collect::<HashSet<_>>();
18574            for buffer_id in buffer_ids {
18575                self.fold_buffer(buffer_id, cx);
18576            }
18577        }
18578    }
18579
18580    pub fn toggle_fold_all(
18581        &mut self,
18582        _: &actions::ToggleFoldAll,
18583        window: &mut Window,
18584        cx: &mut Context<Self>,
18585    ) {
18586        if self.buffer.read(cx).is_singleton() {
18587            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18588            let has_folds = display_map
18589                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
18590                .next()
18591                .is_some();
18592
18593            if has_folds {
18594                self.unfold_all(&actions::UnfoldAll, window, cx);
18595            } else {
18596                self.fold_all(&actions::FoldAll, window, cx);
18597            }
18598        } else {
18599            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18600            let should_unfold = buffer_ids
18601                .iter()
18602                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18603
18604            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18605                editor
18606                    .update_in(cx, |editor, _, cx| {
18607                        for buffer_id in buffer_ids {
18608                            if should_unfold {
18609                                editor.unfold_buffer(buffer_id, cx);
18610                            } else {
18611                                editor.fold_buffer(buffer_id, cx);
18612                            }
18613                        }
18614                    })
18615                    .ok();
18616            });
18617        }
18618    }
18619
18620    fn fold_at_level(
18621        &mut self,
18622        fold_at: &FoldAtLevel,
18623        window: &mut Window,
18624        cx: &mut Context<Self>,
18625    ) {
18626        if !self.buffer.read(cx).is_singleton() {
18627            return;
18628        }
18629
18630        let fold_at_level = fold_at.0;
18631        let snapshot = self.buffer.read(cx).snapshot(cx);
18632        let mut to_fold = Vec::new();
18633        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18634
18635        let row_ranges_to_keep: Vec<Range<u32>> = self
18636            .selections
18637            .all::<Point>(&self.display_snapshot(cx))
18638            .into_iter()
18639            .map(|sel| sel.start.row..sel.end.row)
18640            .collect();
18641
18642        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18643            while start_row < end_row {
18644                match self
18645                    .snapshot(window, cx)
18646                    .crease_for_buffer_row(MultiBufferRow(start_row))
18647                {
18648                    Some(crease) => {
18649                        let nested_start_row = crease.range().start.row + 1;
18650                        let nested_end_row = crease.range().end.row;
18651
18652                        if current_level < fold_at_level {
18653                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18654                        } else if current_level == fold_at_level {
18655                            // Fold iff there is no selection completely contained within the fold region
18656                            if !row_ranges_to_keep.iter().any(|selection| {
18657                                selection.end >= nested_start_row
18658                                    && selection.start <= nested_end_row
18659                            }) {
18660                                to_fold.push(crease);
18661                            }
18662                        }
18663
18664                        start_row = nested_end_row + 1;
18665                    }
18666                    None => start_row += 1,
18667                }
18668            }
18669        }
18670
18671        self.fold_creases(to_fold, true, window, cx);
18672    }
18673
18674    pub fn fold_at_level_1(
18675        &mut self,
18676        _: &actions::FoldAtLevel1,
18677        window: &mut Window,
18678        cx: &mut Context<Self>,
18679    ) {
18680        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18681    }
18682
18683    pub fn fold_at_level_2(
18684        &mut self,
18685        _: &actions::FoldAtLevel2,
18686        window: &mut Window,
18687        cx: &mut Context<Self>,
18688    ) {
18689        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18690    }
18691
18692    pub fn fold_at_level_3(
18693        &mut self,
18694        _: &actions::FoldAtLevel3,
18695        window: &mut Window,
18696        cx: &mut Context<Self>,
18697    ) {
18698        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18699    }
18700
18701    pub fn fold_at_level_4(
18702        &mut self,
18703        _: &actions::FoldAtLevel4,
18704        window: &mut Window,
18705        cx: &mut Context<Self>,
18706    ) {
18707        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18708    }
18709
18710    pub fn fold_at_level_5(
18711        &mut self,
18712        _: &actions::FoldAtLevel5,
18713        window: &mut Window,
18714        cx: &mut Context<Self>,
18715    ) {
18716        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18717    }
18718
18719    pub fn fold_at_level_6(
18720        &mut self,
18721        _: &actions::FoldAtLevel6,
18722        window: &mut Window,
18723        cx: &mut Context<Self>,
18724    ) {
18725        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18726    }
18727
18728    pub fn fold_at_level_7(
18729        &mut self,
18730        _: &actions::FoldAtLevel7,
18731        window: &mut Window,
18732        cx: &mut Context<Self>,
18733    ) {
18734        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18735    }
18736
18737    pub fn fold_at_level_8(
18738        &mut self,
18739        _: &actions::FoldAtLevel8,
18740        window: &mut Window,
18741        cx: &mut Context<Self>,
18742    ) {
18743        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18744    }
18745
18746    pub fn fold_at_level_9(
18747        &mut self,
18748        _: &actions::FoldAtLevel9,
18749        window: &mut Window,
18750        cx: &mut Context<Self>,
18751    ) {
18752        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18753    }
18754
18755    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18756        if self.buffer.read(cx).is_singleton() {
18757            let mut fold_ranges = Vec::new();
18758            let snapshot = self.buffer.read(cx).snapshot(cx);
18759
18760            for row in 0..snapshot.max_row().0 {
18761                if let Some(foldable_range) = self
18762                    .snapshot(window, cx)
18763                    .crease_for_buffer_row(MultiBufferRow(row))
18764                {
18765                    fold_ranges.push(foldable_range);
18766                }
18767            }
18768
18769            self.fold_creases(fold_ranges, true, window, cx);
18770        } else {
18771            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18772                editor
18773                    .update_in(cx, |editor, _, cx| {
18774                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18775                            editor.fold_buffer(buffer_id, cx);
18776                        }
18777                    })
18778                    .ok();
18779            });
18780        }
18781    }
18782
18783    pub fn fold_function_bodies(
18784        &mut self,
18785        _: &actions::FoldFunctionBodies,
18786        window: &mut Window,
18787        cx: &mut Context<Self>,
18788    ) {
18789        let snapshot = self.buffer.read(cx).snapshot(cx);
18790
18791        let ranges = snapshot
18792            .text_object_ranges(
18793                MultiBufferOffset(0)..snapshot.len(),
18794                TreeSitterOptions::default(),
18795            )
18796            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18797            .collect::<Vec<_>>();
18798
18799        let creases = ranges
18800            .into_iter()
18801            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18802            .collect();
18803
18804        self.fold_creases(creases, true, window, cx);
18805    }
18806
18807    pub fn fold_recursive(
18808        &mut self,
18809        _: &actions::FoldRecursive,
18810        window: &mut Window,
18811        cx: &mut Context<Self>,
18812    ) {
18813        let mut to_fold = Vec::new();
18814        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18815        let selections = self.selections.all_adjusted(&display_map);
18816
18817        for selection in selections {
18818            let range = selection.range().sorted();
18819            let buffer_start_row = range.start.row;
18820
18821            if range.start.row != range.end.row {
18822                let mut found = false;
18823                for row in range.start.row..=range.end.row {
18824                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18825                        found = true;
18826                        to_fold.push(crease);
18827                    }
18828                }
18829                if found {
18830                    continue;
18831                }
18832            }
18833
18834            for row in (0..=range.start.row).rev() {
18835                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18836                    if crease.range().end.row >= buffer_start_row {
18837                        to_fold.push(crease);
18838                    } else {
18839                        break;
18840                    }
18841                }
18842            }
18843        }
18844
18845        self.fold_creases(to_fold, true, window, cx);
18846    }
18847
18848    pub fn fold_at(
18849        &mut self,
18850        buffer_row: MultiBufferRow,
18851        window: &mut Window,
18852        cx: &mut Context<Self>,
18853    ) {
18854        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18855
18856        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18857            let autoscroll = self
18858                .selections
18859                .all::<Point>(&display_map)
18860                .iter()
18861                .any(|selection| crease.range().overlaps(&selection.range()));
18862
18863            self.fold_creases(vec![crease], autoscroll, window, cx);
18864        }
18865    }
18866
18867    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18868        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18869            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18870            let buffer = display_map.buffer_snapshot();
18871            let selections = self.selections.all::<Point>(&display_map);
18872            let ranges = selections
18873                .iter()
18874                .map(|s| {
18875                    let range = s.display_range(&display_map).sorted();
18876                    let mut start = range.start.to_point(&display_map);
18877                    let mut end = range.end.to_point(&display_map);
18878                    start.column = 0;
18879                    end.column = buffer.line_len(MultiBufferRow(end.row));
18880                    start..end
18881                })
18882                .collect::<Vec<_>>();
18883
18884            self.unfold_ranges(&ranges, true, true, cx);
18885        } else {
18886            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18887            let buffer_ids = self
18888                .selections
18889                .disjoint_anchor_ranges()
18890                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18891                .collect::<HashSet<_>>();
18892            for buffer_id in buffer_ids {
18893                self.unfold_buffer(buffer_id, cx);
18894            }
18895        }
18896    }
18897
18898    pub fn unfold_recursive(
18899        &mut self,
18900        _: &UnfoldRecursive,
18901        _window: &mut Window,
18902        cx: &mut Context<Self>,
18903    ) {
18904        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18905        let selections = self.selections.all::<Point>(&display_map);
18906        let ranges = selections
18907            .iter()
18908            .map(|s| {
18909                let mut range = s.display_range(&display_map).sorted();
18910                *range.start.column_mut() = 0;
18911                *range.end.column_mut() = display_map.line_len(range.end.row());
18912                let start = range.start.to_point(&display_map);
18913                let end = range.end.to_point(&display_map);
18914                start..end
18915            })
18916            .collect::<Vec<_>>();
18917
18918        self.unfold_ranges(&ranges, true, true, cx);
18919    }
18920
18921    pub fn unfold_at(
18922        &mut self,
18923        buffer_row: MultiBufferRow,
18924        _window: &mut Window,
18925        cx: &mut Context<Self>,
18926    ) {
18927        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18928
18929        let intersection_range = Point::new(buffer_row.0, 0)
18930            ..Point::new(
18931                buffer_row.0,
18932                display_map.buffer_snapshot().line_len(buffer_row),
18933            );
18934
18935        let autoscroll = self
18936            .selections
18937            .all::<Point>(&display_map)
18938            .iter()
18939            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18940
18941        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18942    }
18943
18944    pub fn unfold_all(
18945        &mut self,
18946        _: &actions::UnfoldAll,
18947        _window: &mut Window,
18948        cx: &mut Context<Self>,
18949    ) {
18950        if self.buffer.read(cx).is_singleton() {
18951            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18952            self.unfold_ranges(
18953                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
18954                true,
18955                true,
18956                cx,
18957            );
18958        } else {
18959            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18960                editor
18961                    .update(cx, |editor, cx| {
18962                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18963                            editor.unfold_buffer(buffer_id, cx);
18964                        }
18965                    })
18966                    .ok();
18967            });
18968        }
18969    }
18970
18971    pub fn fold_selected_ranges(
18972        &mut self,
18973        _: &FoldSelectedRanges,
18974        window: &mut Window,
18975        cx: &mut Context<Self>,
18976    ) {
18977        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18978        let selections = self.selections.all_adjusted(&display_map);
18979        let ranges = selections
18980            .into_iter()
18981            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18982            .collect::<Vec<_>>();
18983        self.fold_creases(ranges, true, window, cx);
18984    }
18985
18986    pub fn fold_ranges<T: ToOffset + Clone>(
18987        &mut self,
18988        ranges: Vec<Range<T>>,
18989        auto_scroll: bool,
18990        window: &mut Window,
18991        cx: &mut Context<Self>,
18992    ) {
18993        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18994        let ranges = ranges
18995            .into_iter()
18996            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18997            .collect::<Vec<_>>();
18998        self.fold_creases(ranges, auto_scroll, window, cx);
18999    }
19000
19001    pub fn fold_creases<T: ToOffset + Clone>(
19002        &mut self,
19003        creases: Vec<Crease<T>>,
19004        auto_scroll: bool,
19005        _window: &mut Window,
19006        cx: &mut Context<Self>,
19007    ) {
19008        if creases.is_empty() {
19009            return;
19010        }
19011
19012        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19013
19014        if auto_scroll {
19015            self.request_autoscroll(Autoscroll::fit(), cx);
19016        }
19017
19018        cx.notify();
19019
19020        self.scrollbar_marker_state.dirty = true;
19021        self.folds_did_change(cx);
19022    }
19023
19024    /// Removes any folds whose ranges intersect any of the given ranges.
19025    pub fn unfold_ranges<T: ToOffset + Clone>(
19026        &mut self,
19027        ranges: &[Range<T>],
19028        inclusive: bool,
19029        auto_scroll: bool,
19030        cx: &mut Context<Self>,
19031    ) {
19032        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19033            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19034        });
19035        self.folds_did_change(cx);
19036    }
19037
19038    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19039        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19040            return;
19041        }
19042
19043        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19044        self.display_map.update(cx, |display_map, cx| {
19045            display_map.fold_buffers([buffer_id], cx)
19046        });
19047
19048        let snapshot = self.display_snapshot(cx);
19049        self.selections.change_with(&snapshot, |selections| {
19050            selections.remove_selections_from_buffer(buffer_id);
19051        });
19052
19053        cx.emit(EditorEvent::BufferFoldToggled {
19054            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19055            folded: true,
19056        });
19057        cx.notify();
19058    }
19059
19060    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19061        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19062            return;
19063        }
19064        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19065        self.display_map.update(cx, |display_map, cx| {
19066            display_map.unfold_buffers([buffer_id], cx);
19067        });
19068        cx.emit(EditorEvent::BufferFoldToggled {
19069            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19070            folded: false,
19071        });
19072        cx.notify();
19073    }
19074
19075    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19076        self.display_map.read(cx).is_buffer_folded(buffer)
19077    }
19078
19079    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19080        self.display_map.read(cx).folded_buffers()
19081    }
19082
19083    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19084        self.display_map.update(cx, |display_map, cx| {
19085            display_map.disable_header_for_buffer(buffer_id, cx);
19086        });
19087        cx.notify();
19088    }
19089
19090    /// Removes any folds with the given ranges.
19091    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19092        &mut self,
19093        ranges: &[Range<T>],
19094        type_id: TypeId,
19095        auto_scroll: bool,
19096        cx: &mut Context<Self>,
19097    ) {
19098        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19099            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19100        });
19101        self.folds_did_change(cx);
19102    }
19103
19104    fn remove_folds_with<T: ToOffset + Clone>(
19105        &mut self,
19106        ranges: &[Range<T>],
19107        auto_scroll: bool,
19108        cx: &mut Context<Self>,
19109        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19110    ) {
19111        if ranges.is_empty() {
19112            return;
19113        }
19114
19115        let mut buffers_affected = HashSet::default();
19116        let multi_buffer = self.buffer().read(cx);
19117        for range in ranges {
19118            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19119                buffers_affected.insert(buffer.read(cx).remote_id());
19120            };
19121        }
19122
19123        self.display_map.update(cx, update);
19124
19125        if auto_scroll {
19126            self.request_autoscroll(Autoscroll::fit(), cx);
19127        }
19128
19129        cx.notify();
19130        self.scrollbar_marker_state.dirty = true;
19131        self.active_indent_guides_state.dirty = true;
19132    }
19133
19134    pub fn update_renderer_widths(
19135        &mut self,
19136        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19137        cx: &mut Context<Self>,
19138    ) -> bool {
19139        self.display_map
19140            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19141    }
19142
19143    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19144        self.display_map.read(cx).fold_placeholder.clone()
19145    }
19146
19147    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19148        self.buffer.update(cx, |buffer, cx| {
19149            buffer.set_all_diff_hunks_expanded(cx);
19150        });
19151    }
19152
19153    pub fn expand_all_diff_hunks(
19154        &mut self,
19155        _: &ExpandAllDiffHunks,
19156        _window: &mut Window,
19157        cx: &mut Context<Self>,
19158    ) {
19159        self.buffer.update(cx, |buffer, cx| {
19160            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19161        });
19162    }
19163
19164    pub fn collapse_all_diff_hunks(
19165        &mut self,
19166        _: &CollapseAllDiffHunks,
19167        _window: &mut Window,
19168        cx: &mut Context<Self>,
19169    ) {
19170        self.buffer.update(cx, |buffer, cx| {
19171            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19172        });
19173    }
19174
19175    pub fn toggle_selected_diff_hunks(
19176        &mut self,
19177        _: &ToggleSelectedDiffHunks,
19178        _window: &mut Window,
19179        cx: &mut Context<Self>,
19180    ) {
19181        let ranges: Vec<_> = self
19182            .selections
19183            .disjoint_anchors()
19184            .iter()
19185            .map(|s| s.range())
19186            .collect();
19187        self.toggle_diff_hunks_in_ranges(ranges, cx);
19188    }
19189
19190    pub fn diff_hunks_in_ranges<'a>(
19191        &'a self,
19192        ranges: &'a [Range<Anchor>],
19193        buffer: &'a MultiBufferSnapshot,
19194    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19195        ranges.iter().flat_map(move |range| {
19196            let end_excerpt_id = range.end.excerpt_id;
19197            let range = range.to_point(buffer);
19198            let mut peek_end = range.end;
19199            if range.end.row < buffer.max_row().0 {
19200                peek_end = Point::new(range.end.row + 1, 0);
19201            }
19202            buffer
19203                .diff_hunks_in_range(range.start..peek_end)
19204                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19205        })
19206    }
19207
19208    pub fn has_stageable_diff_hunks_in_ranges(
19209        &self,
19210        ranges: &[Range<Anchor>],
19211        snapshot: &MultiBufferSnapshot,
19212    ) -> bool {
19213        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19214        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19215    }
19216
19217    pub fn toggle_staged_selected_diff_hunks(
19218        &mut self,
19219        _: &::git::ToggleStaged,
19220        _: &mut Window,
19221        cx: &mut Context<Self>,
19222    ) {
19223        let snapshot = self.buffer.read(cx).snapshot(cx);
19224        let ranges: Vec<_> = self
19225            .selections
19226            .disjoint_anchors()
19227            .iter()
19228            .map(|s| s.range())
19229            .collect();
19230        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19231        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19232    }
19233
19234    pub fn set_render_diff_hunk_controls(
19235        &mut self,
19236        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19237        cx: &mut Context<Self>,
19238    ) {
19239        self.render_diff_hunk_controls = render_diff_hunk_controls;
19240        cx.notify();
19241    }
19242
19243    pub fn stage_and_next(
19244        &mut self,
19245        _: &::git::StageAndNext,
19246        window: &mut Window,
19247        cx: &mut Context<Self>,
19248    ) {
19249        self.do_stage_or_unstage_and_next(true, window, cx);
19250    }
19251
19252    pub fn unstage_and_next(
19253        &mut self,
19254        _: &::git::UnstageAndNext,
19255        window: &mut Window,
19256        cx: &mut Context<Self>,
19257    ) {
19258        self.do_stage_or_unstage_and_next(false, window, cx);
19259    }
19260
19261    pub fn stage_or_unstage_diff_hunks(
19262        &mut self,
19263        stage: bool,
19264        ranges: Vec<Range<Anchor>>,
19265        cx: &mut Context<Self>,
19266    ) {
19267        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19268        cx.spawn(async move |this, cx| {
19269            task.await?;
19270            this.update(cx, |this, cx| {
19271                let snapshot = this.buffer.read(cx).snapshot(cx);
19272                let chunk_by = this
19273                    .diff_hunks_in_ranges(&ranges, &snapshot)
19274                    .chunk_by(|hunk| hunk.buffer_id);
19275                for (buffer_id, hunks) in &chunk_by {
19276                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19277                }
19278            })
19279        })
19280        .detach_and_log_err(cx);
19281    }
19282
19283    fn save_buffers_for_ranges_if_needed(
19284        &mut self,
19285        ranges: &[Range<Anchor>],
19286        cx: &mut Context<Editor>,
19287    ) -> Task<Result<()>> {
19288        let multibuffer = self.buffer.read(cx);
19289        let snapshot = multibuffer.read(cx);
19290        let buffer_ids: HashSet<_> = ranges
19291            .iter()
19292            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19293            .collect();
19294        drop(snapshot);
19295
19296        let mut buffers = HashSet::default();
19297        for buffer_id in buffer_ids {
19298            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19299                let buffer = buffer_entity.read(cx);
19300                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19301                {
19302                    buffers.insert(buffer_entity);
19303                }
19304            }
19305        }
19306
19307        if let Some(project) = &self.project {
19308            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19309        } else {
19310            Task::ready(Ok(()))
19311        }
19312    }
19313
19314    fn do_stage_or_unstage_and_next(
19315        &mut self,
19316        stage: bool,
19317        window: &mut Window,
19318        cx: &mut Context<Self>,
19319    ) {
19320        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19321
19322        if ranges.iter().any(|range| range.start != range.end) {
19323            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19324            return;
19325        }
19326
19327        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19328        let snapshot = self.snapshot(window, cx);
19329        let position = self
19330            .selections
19331            .newest::<Point>(&snapshot.display_snapshot)
19332            .head();
19333        let mut row = snapshot
19334            .buffer_snapshot()
19335            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19336            .find(|hunk| hunk.row_range.start.0 > position.row)
19337            .map(|hunk| hunk.row_range.start);
19338
19339        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19340        // Outside of the project diff editor, wrap around to the beginning.
19341        if !all_diff_hunks_expanded {
19342            row = row.or_else(|| {
19343                snapshot
19344                    .buffer_snapshot()
19345                    .diff_hunks_in_range(Point::zero()..position)
19346                    .find(|hunk| hunk.row_range.end.0 < position.row)
19347                    .map(|hunk| hunk.row_range.start)
19348            });
19349        }
19350
19351        if let Some(row) = row {
19352            let destination = Point::new(row.0, 0);
19353            let autoscroll = Autoscroll::center();
19354
19355            self.unfold_ranges(&[destination..destination], false, false, cx);
19356            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19357                s.select_ranges([destination..destination]);
19358            });
19359        }
19360    }
19361
19362    fn do_stage_or_unstage(
19363        &self,
19364        stage: bool,
19365        buffer_id: BufferId,
19366        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19367        cx: &mut App,
19368    ) -> Option<()> {
19369        let project = self.project()?;
19370        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19371        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19372        let buffer_snapshot = buffer.read(cx).snapshot();
19373        let file_exists = buffer_snapshot
19374            .file()
19375            .is_some_and(|file| file.disk_state().exists());
19376        diff.update(cx, |diff, cx| {
19377            diff.stage_or_unstage_hunks(
19378                stage,
19379                &hunks
19380                    .map(|hunk| buffer_diff::DiffHunk {
19381                        buffer_range: hunk.buffer_range,
19382                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19383                            ..hunk.diff_base_byte_range.end.0,
19384                        secondary_status: hunk.secondary_status,
19385                        range: Point::zero()..Point::zero(), // unused
19386                    })
19387                    .collect::<Vec<_>>(),
19388                &buffer_snapshot,
19389                file_exists,
19390                cx,
19391            )
19392        });
19393        None
19394    }
19395
19396    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19397        let ranges: Vec<_> = self
19398            .selections
19399            .disjoint_anchors()
19400            .iter()
19401            .map(|s| s.range())
19402            .collect();
19403        self.buffer
19404            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19405    }
19406
19407    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19408        self.buffer.update(cx, |buffer, cx| {
19409            let ranges = vec![Anchor::min()..Anchor::max()];
19410            if !buffer.all_diff_hunks_expanded()
19411                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19412            {
19413                buffer.collapse_diff_hunks(ranges, cx);
19414                true
19415            } else {
19416                false
19417            }
19418        })
19419    }
19420
19421    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19422        if self.buffer.read(cx).all_diff_hunks_expanded() {
19423            return true;
19424        }
19425        let ranges = vec![Anchor::min()..Anchor::max()];
19426        self.buffer
19427            .read(cx)
19428            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19429    }
19430
19431    fn toggle_diff_hunks_in_ranges(
19432        &mut self,
19433        ranges: Vec<Range<Anchor>>,
19434        cx: &mut Context<Editor>,
19435    ) {
19436        self.buffer.update(cx, |buffer, cx| {
19437            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19438            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19439        })
19440    }
19441
19442    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19443        self.buffer.update(cx, |buffer, cx| {
19444            let snapshot = buffer.snapshot(cx);
19445            let excerpt_id = range.end.excerpt_id;
19446            let point_range = range.to_point(&snapshot);
19447            let expand = !buffer.single_hunk_is_expanded(range, cx);
19448            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19449        })
19450    }
19451
19452    pub(crate) fn apply_all_diff_hunks(
19453        &mut self,
19454        _: &ApplyAllDiffHunks,
19455        window: &mut Window,
19456        cx: &mut Context<Self>,
19457    ) {
19458        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19459
19460        let buffers = self.buffer.read(cx).all_buffers();
19461        for branch_buffer in buffers {
19462            branch_buffer.update(cx, |branch_buffer, cx| {
19463                branch_buffer.merge_into_base(Vec::new(), cx);
19464            });
19465        }
19466
19467        if let Some(project) = self.project.clone() {
19468            self.save(
19469                SaveOptions {
19470                    format: true,
19471                    autosave: false,
19472                },
19473                project,
19474                window,
19475                cx,
19476            )
19477            .detach_and_log_err(cx);
19478        }
19479    }
19480
19481    pub(crate) fn apply_selected_diff_hunks(
19482        &mut self,
19483        _: &ApplyDiffHunk,
19484        window: &mut Window,
19485        cx: &mut Context<Self>,
19486    ) {
19487        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19488        let snapshot = self.snapshot(window, cx);
19489        let hunks = snapshot.hunks_for_ranges(
19490            self.selections
19491                .all(&snapshot.display_snapshot)
19492                .into_iter()
19493                .map(|selection| selection.range()),
19494        );
19495        let mut ranges_by_buffer = HashMap::default();
19496        self.transact(window, cx, |editor, _window, cx| {
19497            for hunk in hunks {
19498                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19499                    ranges_by_buffer
19500                        .entry(buffer.clone())
19501                        .or_insert_with(Vec::new)
19502                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19503                }
19504            }
19505
19506            for (buffer, ranges) in ranges_by_buffer {
19507                buffer.update(cx, |buffer, cx| {
19508                    buffer.merge_into_base(ranges, cx);
19509                });
19510            }
19511        });
19512
19513        if let Some(project) = self.project.clone() {
19514            self.save(
19515                SaveOptions {
19516                    format: true,
19517                    autosave: false,
19518                },
19519                project,
19520                window,
19521                cx,
19522            )
19523            .detach_and_log_err(cx);
19524        }
19525    }
19526
19527    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19528        if hovered != self.gutter_hovered {
19529            self.gutter_hovered = hovered;
19530            cx.notify();
19531        }
19532    }
19533
19534    pub fn insert_blocks(
19535        &mut self,
19536        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19537        autoscroll: Option<Autoscroll>,
19538        cx: &mut Context<Self>,
19539    ) -> Vec<CustomBlockId> {
19540        let blocks = self
19541            .display_map
19542            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19543        if let Some(autoscroll) = autoscroll {
19544            self.request_autoscroll(autoscroll, cx);
19545        }
19546        cx.notify();
19547        blocks
19548    }
19549
19550    pub fn resize_blocks(
19551        &mut self,
19552        heights: HashMap<CustomBlockId, u32>,
19553        autoscroll: Option<Autoscroll>,
19554        cx: &mut Context<Self>,
19555    ) {
19556        self.display_map
19557            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19558        if let Some(autoscroll) = autoscroll {
19559            self.request_autoscroll(autoscroll, cx);
19560        }
19561        cx.notify();
19562    }
19563
19564    pub fn replace_blocks(
19565        &mut self,
19566        renderers: HashMap<CustomBlockId, RenderBlock>,
19567        autoscroll: Option<Autoscroll>,
19568        cx: &mut Context<Self>,
19569    ) {
19570        self.display_map
19571            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19572        if let Some(autoscroll) = autoscroll {
19573            self.request_autoscroll(autoscroll, cx);
19574        }
19575        cx.notify();
19576    }
19577
19578    pub fn remove_blocks(
19579        &mut self,
19580        block_ids: HashSet<CustomBlockId>,
19581        autoscroll: Option<Autoscroll>,
19582        cx: &mut Context<Self>,
19583    ) {
19584        self.display_map.update(cx, |display_map, cx| {
19585            display_map.remove_blocks(block_ids, cx)
19586        });
19587        if let Some(autoscroll) = autoscroll {
19588            self.request_autoscroll(autoscroll, cx);
19589        }
19590        cx.notify();
19591    }
19592
19593    pub fn row_for_block(
19594        &self,
19595        block_id: CustomBlockId,
19596        cx: &mut Context<Self>,
19597    ) -> Option<DisplayRow> {
19598        self.display_map
19599            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19600    }
19601
19602    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19603        self.focused_block = Some(focused_block);
19604    }
19605
19606    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19607        self.focused_block.take()
19608    }
19609
19610    pub fn insert_creases(
19611        &mut self,
19612        creases: impl IntoIterator<Item = Crease<Anchor>>,
19613        cx: &mut Context<Self>,
19614    ) -> Vec<CreaseId> {
19615        self.display_map
19616            .update(cx, |map, cx| map.insert_creases(creases, cx))
19617    }
19618
19619    pub fn remove_creases(
19620        &mut self,
19621        ids: impl IntoIterator<Item = CreaseId>,
19622        cx: &mut Context<Self>,
19623    ) -> Vec<(CreaseId, Range<Anchor>)> {
19624        self.display_map
19625            .update(cx, |map, cx| map.remove_creases(ids, cx))
19626    }
19627
19628    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19629        self.display_map
19630            .update(cx, |map, cx| map.snapshot(cx))
19631            .longest_row()
19632    }
19633
19634    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19635        self.display_map
19636            .update(cx, |map, cx| map.snapshot(cx))
19637            .max_point()
19638    }
19639
19640    pub fn text(&self, cx: &App) -> String {
19641        self.buffer.read(cx).read(cx).text()
19642    }
19643
19644    pub fn is_empty(&self, cx: &App) -> bool {
19645        self.buffer.read(cx).read(cx).is_empty()
19646    }
19647
19648    pub fn text_option(&self, cx: &App) -> Option<String> {
19649        let text = self.text(cx);
19650        let text = text.trim();
19651
19652        if text.is_empty() {
19653            return None;
19654        }
19655
19656        Some(text.to_string())
19657    }
19658
19659    pub fn set_text(
19660        &mut self,
19661        text: impl Into<Arc<str>>,
19662        window: &mut Window,
19663        cx: &mut Context<Self>,
19664    ) {
19665        self.transact(window, cx, |this, _, cx| {
19666            this.buffer
19667                .read(cx)
19668                .as_singleton()
19669                .expect("you can only call set_text on editors for singleton buffers")
19670                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19671        });
19672    }
19673
19674    pub fn display_text(&self, cx: &mut App) -> String {
19675        self.display_map
19676            .update(cx, |map, cx| map.snapshot(cx))
19677            .text()
19678    }
19679
19680    fn create_minimap(
19681        &self,
19682        minimap_settings: MinimapSettings,
19683        window: &mut Window,
19684        cx: &mut Context<Self>,
19685    ) -> Option<Entity<Self>> {
19686        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19687            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19688    }
19689
19690    fn initialize_new_minimap(
19691        &self,
19692        minimap_settings: MinimapSettings,
19693        window: &mut Window,
19694        cx: &mut Context<Self>,
19695    ) -> Entity<Self> {
19696        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19697
19698        let mut minimap = Editor::new_internal(
19699            EditorMode::Minimap {
19700                parent: cx.weak_entity(),
19701            },
19702            self.buffer.clone(),
19703            None,
19704            Some(self.display_map.clone()),
19705            window,
19706            cx,
19707        );
19708        minimap.scroll_manager.clone_state(&self.scroll_manager);
19709        minimap.set_text_style_refinement(TextStyleRefinement {
19710            font_size: Some(MINIMAP_FONT_SIZE),
19711            font_weight: Some(MINIMAP_FONT_WEIGHT),
19712            ..Default::default()
19713        });
19714        minimap.update_minimap_configuration(minimap_settings, cx);
19715        cx.new(|_| minimap)
19716    }
19717
19718    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19719        let current_line_highlight = minimap_settings
19720            .current_line_highlight
19721            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19722        self.set_current_line_highlight(Some(current_line_highlight));
19723    }
19724
19725    pub fn minimap(&self) -> Option<&Entity<Self>> {
19726        self.minimap
19727            .as_ref()
19728            .filter(|_| self.minimap_visibility.visible())
19729    }
19730
19731    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19732        let mut wrap_guides = smallvec![];
19733
19734        if self.show_wrap_guides == Some(false) {
19735            return wrap_guides;
19736        }
19737
19738        let settings = self.buffer.read(cx).language_settings(cx);
19739        if settings.show_wrap_guides {
19740            match self.soft_wrap_mode(cx) {
19741                SoftWrap::Column(soft_wrap) => {
19742                    wrap_guides.push((soft_wrap as usize, true));
19743                }
19744                SoftWrap::Bounded(soft_wrap) => {
19745                    wrap_guides.push((soft_wrap as usize, true));
19746                }
19747                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19748            }
19749            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19750        }
19751
19752        wrap_guides
19753    }
19754
19755    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19756        let settings = self.buffer.read(cx).language_settings(cx);
19757        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19758        match mode {
19759            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19760                SoftWrap::None
19761            }
19762            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19763            language_settings::SoftWrap::PreferredLineLength => {
19764                SoftWrap::Column(settings.preferred_line_length)
19765            }
19766            language_settings::SoftWrap::Bounded => {
19767                SoftWrap::Bounded(settings.preferred_line_length)
19768            }
19769        }
19770    }
19771
19772    pub fn set_soft_wrap_mode(
19773        &mut self,
19774        mode: language_settings::SoftWrap,
19775
19776        cx: &mut Context<Self>,
19777    ) {
19778        self.soft_wrap_mode_override = Some(mode);
19779        cx.notify();
19780    }
19781
19782    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19783        self.hard_wrap = hard_wrap;
19784        cx.notify();
19785    }
19786
19787    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19788        self.text_style_refinement = Some(style);
19789    }
19790
19791    /// called by the Element so we know what style we were most recently rendered with.
19792    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19793        // We intentionally do not inform the display map about the minimap style
19794        // so that wrapping is not recalculated and stays consistent for the editor
19795        // and its linked minimap.
19796        if !self.mode.is_minimap() {
19797            let font = style.text.font();
19798            let font_size = style.text.font_size.to_pixels(window.rem_size());
19799            let display_map = self
19800                .placeholder_display_map
19801                .as_ref()
19802                .filter(|_| self.is_empty(cx))
19803                .unwrap_or(&self.display_map);
19804
19805            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19806        }
19807        self.style = Some(style);
19808    }
19809
19810    pub fn style(&self) -> Option<&EditorStyle> {
19811        self.style.as_ref()
19812    }
19813
19814    // Called by the element. This method is not designed to be called outside of the editor
19815    // element's layout code because it does not notify when rewrapping is computed synchronously.
19816    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19817        if self.is_empty(cx) {
19818            self.placeholder_display_map
19819                .as_ref()
19820                .map_or(false, |display_map| {
19821                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19822                })
19823        } else {
19824            self.display_map
19825                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19826        }
19827    }
19828
19829    pub fn set_soft_wrap(&mut self) {
19830        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19831    }
19832
19833    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19834        if self.soft_wrap_mode_override.is_some() {
19835            self.soft_wrap_mode_override.take();
19836        } else {
19837            let soft_wrap = match self.soft_wrap_mode(cx) {
19838                SoftWrap::GitDiff => return,
19839                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19840                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19841                    language_settings::SoftWrap::None
19842                }
19843            };
19844            self.soft_wrap_mode_override = Some(soft_wrap);
19845        }
19846        cx.notify();
19847    }
19848
19849    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19850        let Some(workspace) = self.workspace() else {
19851            return;
19852        };
19853        let fs = workspace.read(cx).app_state().fs.clone();
19854        let current_show = TabBarSettings::get_global(cx).show;
19855        update_settings_file(fs, cx, move |setting, _| {
19856            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19857        });
19858    }
19859
19860    pub fn toggle_indent_guides(
19861        &mut self,
19862        _: &ToggleIndentGuides,
19863        _: &mut Window,
19864        cx: &mut Context<Self>,
19865    ) {
19866        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19867            self.buffer
19868                .read(cx)
19869                .language_settings(cx)
19870                .indent_guides
19871                .enabled
19872        });
19873        self.show_indent_guides = Some(!currently_enabled);
19874        cx.notify();
19875    }
19876
19877    fn should_show_indent_guides(&self) -> Option<bool> {
19878        self.show_indent_guides
19879    }
19880
19881    pub fn toggle_line_numbers(
19882        &mut self,
19883        _: &ToggleLineNumbers,
19884        _: &mut Window,
19885        cx: &mut Context<Self>,
19886    ) {
19887        let mut editor_settings = EditorSettings::get_global(cx).clone();
19888        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19889        EditorSettings::override_global(editor_settings, cx);
19890    }
19891
19892    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19893        if let Some(show_line_numbers) = self.show_line_numbers {
19894            return show_line_numbers;
19895        }
19896        EditorSettings::get_global(cx).gutter.line_numbers
19897    }
19898
19899    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19900        match (
19901            self.use_relative_line_numbers,
19902            EditorSettings::get_global(cx).relative_line_numbers,
19903        ) {
19904            (None, setting) => setting,
19905            (Some(false), _) => RelativeLineNumbers::Disabled,
19906            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19907            (Some(true), _) => RelativeLineNumbers::Enabled,
19908        }
19909    }
19910
19911    pub fn toggle_relative_line_numbers(
19912        &mut self,
19913        _: &ToggleRelativeLineNumbers,
19914        _: &mut Window,
19915        cx: &mut Context<Self>,
19916    ) {
19917        let is_relative = self.relative_line_numbers(cx);
19918        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19919    }
19920
19921    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19922        self.use_relative_line_numbers = is_relative;
19923        cx.notify();
19924    }
19925
19926    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19927        self.show_gutter = show_gutter;
19928        cx.notify();
19929    }
19930
19931    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19932        self.show_scrollbars = ScrollbarAxes {
19933            horizontal: show,
19934            vertical: show,
19935        };
19936        cx.notify();
19937    }
19938
19939    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19940        self.show_scrollbars.vertical = show;
19941        cx.notify();
19942    }
19943
19944    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19945        self.show_scrollbars.horizontal = show;
19946        cx.notify();
19947    }
19948
19949    pub fn set_minimap_visibility(
19950        &mut self,
19951        minimap_visibility: MinimapVisibility,
19952        window: &mut Window,
19953        cx: &mut Context<Self>,
19954    ) {
19955        if self.minimap_visibility != minimap_visibility {
19956            if minimap_visibility.visible() && self.minimap.is_none() {
19957                let minimap_settings = EditorSettings::get_global(cx).minimap;
19958                self.minimap =
19959                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19960            }
19961            self.minimap_visibility = minimap_visibility;
19962            cx.notify();
19963        }
19964    }
19965
19966    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19967        self.set_show_scrollbars(false, cx);
19968        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19969    }
19970
19971    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19972        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19973    }
19974
19975    /// Normally the text in full mode and auto height editors is padded on the
19976    /// left side by roughly half a character width for improved hit testing.
19977    ///
19978    /// Use this method to disable this for cases where this is not wanted (e.g.
19979    /// if you want to align the editor text with some other text above or below)
19980    /// or if you want to add this padding to single-line editors.
19981    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19982        self.offset_content = offset_content;
19983        cx.notify();
19984    }
19985
19986    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19987        self.show_line_numbers = Some(show_line_numbers);
19988        cx.notify();
19989    }
19990
19991    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19992        self.disable_expand_excerpt_buttons = true;
19993        cx.notify();
19994    }
19995
19996    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19997        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19998        cx.notify();
19999    }
20000
20001    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20002        self.show_code_actions = Some(show_code_actions);
20003        cx.notify();
20004    }
20005
20006    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20007        self.show_runnables = Some(show_runnables);
20008        cx.notify();
20009    }
20010
20011    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20012        self.show_breakpoints = Some(show_breakpoints);
20013        cx.notify();
20014    }
20015
20016    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20017        if self.display_map.read(cx).masked != masked {
20018            self.display_map.update(cx, |map, _| map.masked = masked);
20019        }
20020        cx.notify()
20021    }
20022
20023    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20024        self.show_wrap_guides = Some(show_wrap_guides);
20025        cx.notify();
20026    }
20027
20028    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20029        self.show_indent_guides = Some(show_indent_guides);
20030        cx.notify();
20031    }
20032
20033    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20034        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20035            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20036                && let Some(dir) = file.abs_path(cx).parent()
20037            {
20038                return Some(dir.to_owned());
20039            }
20040        }
20041
20042        None
20043    }
20044
20045    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20046        self.active_excerpt(cx)?
20047            .1
20048            .read(cx)
20049            .file()
20050            .and_then(|f| f.as_local())
20051    }
20052
20053    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20054        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20055            let buffer = buffer.read(cx);
20056            if let Some(project_path) = buffer.project_path(cx) {
20057                let project = self.project()?.read(cx);
20058                project.absolute_path(&project_path, cx)
20059            } else {
20060                buffer
20061                    .file()
20062                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20063            }
20064        })
20065    }
20066
20067    pub fn reveal_in_finder(
20068        &mut self,
20069        _: &RevealInFileManager,
20070        _window: &mut Window,
20071        cx: &mut Context<Self>,
20072    ) {
20073        if let Some(target) = self.target_file(cx) {
20074            cx.reveal_path(&target.abs_path(cx));
20075        }
20076    }
20077
20078    pub fn copy_path(
20079        &mut self,
20080        _: &zed_actions::workspace::CopyPath,
20081        _window: &mut Window,
20082        cx: &mut Context<Self>,
20083    ) {
20084        if let Some(path) = self.target_file_abs_path(cx)
20085            && let Some(path) = path.to_str()
20086        {
20087            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20088        } else {
20089            cx.propagate();
20090        }
20091    }
20092
20093    pub fn copy_relative_path(
20094        &mut self,
20095        _: &zed_actions::workspace::CopyRelativePath,
20096        _window: &mut Window,
20097        cx: &mut Context<Self>,
20098    ) {
20099        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20100            let project = self.project()?.read(cx);
20101            let path = buffer.read(cx).file()?.path();
20102            let path = path.display(project.path_style(cx));
20103            Some(path)
20104        }) {
20105            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20106        } else {
20107            cx.propagate();
20108        }
20109    }
20110
20111    /// Returns the project path for the editor's buffer, if any buffer is
20112    /// opened in the editor.
20113    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20114        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20115            buffer.read(cx).project_path(cx)
20116        } else {
20117            None
20118        }
20119    }
20120
20121    // Returns true if the editor handled a go-to-line request
20122    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20123        maybe!({
20124            let breakpoint_store = self.breakpoint_store.as_ref()?;
20125
20126            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20127            else {
20128                self.clear_row_highlights::<ActiveDebugLine>();
20129                return None;
20130            };
20131
20132            let position = active_stack_frame.position;
20133            let buffer_id = position.buffer_id?;
20134            let snapshot = self
20135                .project
20136                .as_ref()?
20137                .read(cx)
20138                .buffer_for_id(buffer_id, cx)?
20139                .read(cx)
20140                .snapshot();
20141
20142            let mut handled = false;
20143            for (id, ExcerptRange { context, .. }) in
20144                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20145            {
20146                if context.start.cmp(&position, &snapshot).is_ge()
20147                    || context.end.cmp(&position, &snapshot).is_lt()
20148                {
20149                    continue;
20150                }
20151                let snapshot = self.buffer.read(cx).snapshot(cx);
20152                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20153
20154                handled = true;
20155                self.clear_row_highlights::<ActiveDebugLine>();
20156
20157                self.go_to_line::<ActiveDebugLine>(
20158                    multibuffer_anchor,
20159                    Some(cx.theme().colors().editor_debugger_active_line_background),
20160                    window,
20161                    cx,
20162                );
20163
20164                cx.notify();
20165            }
20166
20167            handled.then_some(())
20168        })
20169        .is_some()
20170    }
20171
20172    pub fn copy_file_name_without_extension(
20173        &mut self,
20174        _: &CopyFileNameWithoutExtension,
20175        _: &mut Window,
20176        cx: &mut Context<Self>,
20177    ) {
20178        if let Some(file) = self.target_file(cx)
20179            && let Some(file_stem) = file.path().file_stem()
20180        {
20181            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20182        }
20183    }
20184
20185    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20186        if let Some(file) = self.target_file(cx)
20187            && let Some(name) = file.path().file_name()
20188        {
20189            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
20190        }
20191    }
20192
20193    pub fn toggle_git_blame(
20194        &mut self,
20195        _: &::git::Blame,
20196        window: &mut Window,
20197        cx: &mut Context<Self>,
20198    ) {
20199        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20200
20201        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20202            self.start_git_blame(true, window, cx);
20203        }
20204
20205        cx.notify();
20206    }
20207
20208    pub fn toggle_git_blame_inline(
20209        &mut self,
20210        _: &ToggleGitBlameInline,
20211        window: &mut Window,
20212        cx: &mut Context<Self>,
20213    ) {
20214        self.toggle_git_blame_inline_internal(true, window, cx);
20215        cx.notify();
20216    }
20217
20218    pub fn open_git_blame_commit(
20219        &mut self,
20220        _: &OpenGitBlameCommit,
20221        window: &mut Window,
20222        cx: &mut Context<Self>,
20223    ) {
20224        self.open_git_blame_commit_internal(window, cx);
20225    }
20226
20227    fn open_git_blame_commit_internal(
20228        &mut self,
20229        window: &mut Window,
20230        cx: &mut Context<Self>,
20231    ) -> Option<()> {
20232        let blame = self.blame.as_ref()?;
20233        let snapshot = self.snapshot(window, cx);
20234        let cursor = self
20235            .selections
20236            .newest::<Point>(&snapshot.display_snapshot)
20237            .head();
20238        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20239        let (_, blame_entry) = blame
20240            .update(cx, |blame, cx| {
20241                blame
20242                    .blame_for_rows(
20243                        &[RowInfo {
20244                            buffer_id: Some(buffer.remote_id()),
20245                            buffer_row: Some(point.row),
20246                            ..Default::default()
20247                        }],
20248                        cx,
20249                    )
20250                    .next()
20251            })
20252            .flatten()?;
20253        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20254        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20255        let workspace = self.workspace()?.downgrade();
20256        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20257        None
20258    }
20259
20260    pub fn git_blame_inline_enabled(&self) -> bool {
20261        self.git_blame_inline_enabled
20262    }
20263
20264    pub fn toggle_selection_menu(
20265        &mut self,
20266        _: &ToggleSelectionMenu,
20267        _: &mut Window,
20268        cx: &mut Context<Self>,
20269    ) {
20270        self.show_selection_menu = self
20271            .show_selection_menu
20272            .map(|show_selections_menu| !show_selections_menu)
20273            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20274
20275        cx.notify();
20276    }
20277
20278    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20279        self.show_selection_menu
20280            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20281    }
20282
20283    fn start_git_blame(
20284        &mut self,
20285        user_triggered: bool,
20286        window: &mut Window,
20287        cx: &mut Context<Self>,
20288    ) {
20289        if let Some(project) = self.project() {
20290            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20291                && buffer.read(cx).file().is_none()
20292            {
20293                return;
20294            }
20295
20296            let focused = self.focus_handle(cx).contains_focused(window, cx);
20297
20298            let project = project.clone();
20299            let blame = cx
20300                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20301            self.blame_subscription =
20302                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20303            self.blame = Some(blame);
20304        }
20305    }
20306
20307    fn toggle_git_blame_inline_internal(
20308        &mut self,
20309        user_triggered: bool,
20310        window: &mut Window,
20311        cx: &mut Context<Self>,
20312    ) {
20313        if self.git_blame_inline_enabled {
20314            self.git_blame_inline_enabled = false;
20315            self.show_git_blame_inline = false;
20316            self.show_git_blame_inline_delay_task.take();
20317        } else {
20318            self.git_blame_inline_enabled = true;
20319            self.start_git_blame_inline(user_triggered, window, cx);
20320        }
20321
20322        cx.notify();
20323    }
20324
20325    fn start_git_blame_inline(
20326        &mut self,
20327        user_triggered: bool,
20328        window: &mut Window,
20329        cx: &mut Context<Self>,
20330    ) {
20331        self.start_git_blame(user_triggered, window, cx);
20332
20333        if ProjectSettings::get_global(cx)
20334            .git
20335            .inline_blame_delay()
20336            .is_some()
20337        {
20338            self.start_inline_blame_timer(window, cx);
20339        } else {
20340            self.show_git_blame_inline = true
20341        }
20342    }
20343
20344    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20345        self.blame.as_ref()
20346    }
20347
20348    pub fn show_git_blame_gutter(&self) -> bool {
20349        self.show_git_blame_gutter
20350    }
20351
20352    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20353        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20354    }
20355
20356    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20357        self.show_git_blame_inline
20358            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20359            && !self.newest_selection_head_on_empty_line(cx)
20360            && self.has_blame_entries(cx)
20361    }
20362
20363    fn has_blame_entries(&self, cx: &App) -> bool {
20364        self.blame()
20365            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20366    }
20367
20368    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20369        let cursor_anchor = self.selections.newest_anchor().head();
20370
20371        let snapshot = self.buffer.read(cx).snapshot(cx);
20372        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20373
20374        snapshot.line_len(buffer_row) == 0
20375    }
20376
20377    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20378        let buffer_and_selection = maybe!({
20379            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20380            let selection_range = selection.range();
20381
20382            let multi_buffer = self.buffer().read(cx);
20383            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20384            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20385
20386            let (buffer, range, _) = if selection.reversed {
20387                buffer_ranges.first()
20388            } else {
20389                buffer_ranges.last()
20390            }?;
20391
20392            let selection = text::ToPoint::to_point(&range.start, buffer).row
20393                ..text::ToPoint::to_point(&range.end, buffer).row;
20394            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20395        });
20396
20397        let Some((buffer, selection)) = buffer_and_selection else {
20398            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20399        };
20400
20401        let Some(project) = self.project() else {
20402            return Task::ready(Err(anyhow!("editor does not have project")));
20403        };
20404
20405        project.update(cx, |project, cx| {
20406            project.get_permalink_to_line(&buffer, selection, cx)
20407        })
20408    }
20409
20410    pub fn copy_permalink_to_line(
20411        &mut self,
20412        _: &CopyPermalinkToLine,
20413        window: &mut Window,
20414        cx: &mut Context<Self>,
20415    ) {
20416        let permalink_task = self.get_permalink_to_line(cx);
20417        let workspace = self.workspace();
20418
20419        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20420            Ok(permalink) => {
20421                cx.update(|_, cx| {
20422                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20423                })
20424                .ok();
20425            }
20426            Err(err) => {
20427                let message = format!("Failed to copy permalink: {err}");
20428
20429                anyhow::Result::<()>::Err(err).log_err();
20430
20431                if let Some(workspace) = workspace {
20432                    workspace
20433                        .update_in(cx, |workspace, _, cx| {
20434                            struct CopyPermalinkToLine;
20435
20436                            workspace.show_toast(
20437                                Toast::new(
20438                                    NotificationId::unique::<CopyPermalinkToLine>(),
20439                                    message,
20440                                ),
20441                                cx,
20442                            )
20443                        })
20444                        .ok();
20445                }
20446            }
20447        })
20448        .detach();
20449    }
20450
20451    pub fn copy_file_location(
20452        &mut self,
20453        _: &CopyFileLocation,
20454        _: &mut Window,
20455        cx: &mut Context<Self>,
20456    ) {
20457        let selection = self
20458            .selections
20459            .newest::<Point>(&self.display_snapshot(cx))
20460            .start
20461            .row
20462            + 1;
20463        if let Some(file) = self.target_file(cx) {
20464            let path = file.path().display(file.path_style(cx));
20465            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20466        }
20467    }
20468
20469    pub fn open_permalink_to_line(
20470        &mut self,
20471        _: &OpenPermalinkToLine,
20472        window: &mut Window,
20473        cx: &mut Context<Self>,
20474    ) {
20475        let permalink_task = self.get_permalink_to_line(cx);
20476        let workspace = self.workspace();
20477
20478        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20479            Ok(permalink) => {
20480                cx.update(|_, cx| {
20481                    cx.open_url(permalink.as_ref());
20482                })
20483                .ok();
20484            }
20485            Err(err) => {
20486                let message = format!("Failed to open permalink: {err}");
20487
20488                anyhow::Result::<()>::Err(err).log_err();
20489
20490                if let Some(workspace) = workspace {
20491                    workspace
20492                        .update(cx, |workspace, cx| {
20493                            struct OpenPermalinkToLine;
20494
20495                            workspace.show_toast(
20496                                Toast::new(
20497                                    NotificationId::unique::<OpenPermalinkToLine>(),
20498                                    message,
20499                                ),
20500                                cx,
20501                            )
20502                        })
20503                        .ok();
20504                }
20505            }
20506        })
20507        .detach();
20508    }
20509
20510    pub fn insert_uuid_v4(
20511        &mut self,
20512        _: &InsertUuidV4,
20513        window: &mut Window,
20514        cx: &mut Context<Self>,
20515    ) {
20516        self.insert_uuid(UuidVersion::V4, window, cx);
20517    }
20518
20519    pub fn insert_uuid_v7(
20520        &mut self,
20521        _: &InsertUuidV7,
20522        window: &mut Window,
20523        cx: &mut Context<Self>,
20524    ) {
20525        self.insert_uuid(UuidVersion::V7, window, cx);
20526    }
20527
20528    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20529        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20530        self.transact(window, cx, |this, window, cx| {
20531            let edits = this
20532                .selections
20533                .all::<Point>(&this.display_snapshot(cx))
20534                .into_iter()
20535                .map(|selection| {
20536                    let uuid = match version {
20537                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20538                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20539                    };
20540
20541                    (selection.range(), uuid.to_string())
20542                });
20543            this.edit(edits, cx);
20544            this.refresh_edit_prediction(true, false, window, cx);
20545        });
20546    }
20547
20548    pub fn open_selections_in_multibuffer(
20549        &mut self,
20550        _: &OpenSelectionsInMultibuffer,
20551        window: &mut Window,
20552        cx: &mut Context<Self>,
20553    ) {
20554        let multibuffer = self.buffer.read(cx);
20555
20556        let Some(buffer) = multibuffer.as_singleton() else {
20557            return;
20558        };
20559
20560        let Some(workspace) = self.workspace() else {
20561            return;
20562        };
20563
20564        let title = multibuffer.title(cx).to_string();
20565
20566        let locations = self
20567            .selections
20568            .all_anchors(&self.display_snapshot(cx))
20569            .iter()
20570            .map(|selection| {
20571                (
20572                    buffer.clone(),
20573                    (selection.start.text_anchor..selection.end.text_anchor)
20574                        .to_point(buffer.read(cx)),
20575                )
20576            })
20577            .into_group_map();
20578
20579        cx.spawn_in(window, async move |_, cx| {
20580            workspace.update_in(cx, |workspace, window, cx| {
20581                Self::open_locations_in_multibuffer(
20582                    workspace,
20583                    locations,
20584                    format!("Selections for '{title}'"),
20585                    false,
20586                    MultibufferSelectionMode::All,
20587                    window,
20588                    cx,
20589                );
20590            })
20591        })
20592        .detach();
20593    }
20594
20595    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20596    /// last highlight added will be used.
20597    ///
20598    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20599    pub fn highlight_rows<T: 'static>(
20600        &mut self,
20601        range: Range<Anchor>,
20602        color: Hsla,
20603        options: RowHighlightOptions,
20604        cx: &mut Context<Self>,
20605    ) {
20606        let snapshot = self.buffer().read(cx).snapshot(cx);
20607        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20608        let ix = row_highlights.binary_search_by(|highlight| {
20609            Ordering::Equal
20610                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20611                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20612        });
20613
20614        if let Err(mut ix) = ix {
20615            let index = post_inc(&mut self.highlight_order);
20616
20617            // If this range intersects with the preceding highlight, then merge it with
20618            // the preceding highlight. Otherwise insert a new highlight.
20619            let mut merged = false;
20620            if ix > 0 {
20621                let prev_highlight = &mut row_highlights[ix - 1];
20622                if prev_highlight
20623                    .range
20624                    .end
20625                    .cmp(&range.start, &snapshot)
20626                    .is_ge()
20627                {
20628                    ix -= 1;
20629                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20630                        prev_highlight.range.end = range.end;
20631                    }
20632                    merged = true;
20633                    prev_highlight.index = index;
20634                    prev_highlight.color = color;
20635                    prev_highlight.options = options;
20636                }
20637            }
20638
20639            if !merged {
20640                row_highlights.insert(
20641                    ix,
20642                    RowHighlight {
20643                        range,
20644                        index,
20645                        color,
20646                        options,
20647                        type_id: TypeId::of::<T>(),
20648                    },
20649                );
20650            }
20651
20652            // If any of the following highlights intersect with this one, merge them.
20653            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20654                let highlight = &row_highlights[ix];
20655                if next_highlight
20656                    .range
20657                    .start
20658                    .cmp(&highlight.range.end, &snapshot)
20659                    .is_le()
20660                {
20661                    if next_highlight
20662                        .range
20663                        .end
20664                        .cmp(&highlight.range.end, &snapshot)
20665                        .is_gt()
20666                    {
20667                        row_highlights[ix].range.end = next_highlight.range.end;
20668                    }
20669                    row_highlights.remove(ix + 1);
20670                } else {
20671                    break;
20672                }
20673            }
20674        }
20675    }
20676
20677    /// Remove any highlighted row ranges of the given type that intersect the
20678    /// given ranges.
20679    pub fn remove_highlighted_rows<T: 'static>(
20680        &mut self,
20681        ranges_to_remove: Vec<Range<Anchor>>,
20682        cx: &mut Context<Self>,
20683    ) {
20684        let snapshot = self.buffer().read(cx).snapshot(cx);
20685        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20686        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20687        row_highlights.retain(|highlight| {
20688            while let Some(range_to_remove) = ranges_to_remove.peek() {
20689                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20690                    Ordering::Less | Ordering::Equal => {
20691                        ranges_to_remove.next();
20692                    }
20693                    Ordering::Greater => {
20694                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20695                            Ordering::Less | Ordering::Equal => {
20696                                return false;
20697                            }
20698                            Ordering::Greater => break,
20699                        }
20700                    }
20701                }
20702            }
20703
20704            true
20705        })
20706    }
20707
20708    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20709    pub fn clear_row_highlights<T: 'static>(&mut self) {
20710        self.highlighted_rows.remove(&TypeId::of::<T>());
20711    }
20712
20713    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20714    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20715        self.highlighted_rows
20716            .get(&TypeId::of::<T>())
20717            .map_or(&[] as &[_], |vec| vec.as_slice())
20718            .iter()
20719            .map(|highlight| (highlight.range.clone(), highlight.color))
20720    }
20721
20722    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20723    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20724    /// Allows to ignore certain kinds of highlights.
20725    pub fn highlighted_display_rows(
20726        &self,
20727        window: &mut Window,
20728        cx: &mut App,
20729    ) -> BTreeMap<DisplayRow, LineHighlight> {
20730        let snapshot = self.snapshot(window, cx);
20731        let mut used_highlight_orders = HashMap::default();
20732        self.highlighted_rows
20733            .iter()
20734            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20735            .fold(
20736                BTreeMap::<DisplayRow, LineHighlight>::new(),
20737                |mut unique_rows, highlight| {
20738                    let start = highlight.range.start.to_display_point(&snapshot);
20739                    let end = highlight.range.end.to_display_point(&snapshot);
20740                    let start_row = start.row().0;
20741                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20742                        && end.column() == 0
20743                    {
20744                        end.row().0.saturating_sub(1)
20745                    } else {
20746                        end.row().0
20747                    };
20748                    for row in start_row..=end_row {
20749                        let used_index =
20750                            used_highlight_orders.entry(row).or_insert(highlight.index);
20751                        if highlight.index >= *used_index {
20752                            *used_index = highlight.index;
20753                            unique_rows.insert(
20754                                DisplayRow(row),
20755                                LineHighlight {
20756                                    include_gutter: highlight.options.include_gutter,
20757                                    border: None,
20758                                    background: highlight.color.into(),
20759                                    type_id: Some(highlight.type_id),
20760                                },
20761                            );
20762                        }
20763                    }
20764                    unique_rows
20765                },
20766            )
20767    }
20768
20769    pub fn highlighted_display_row_for_autoscroll(
20770        &self,
20771        snapshot: &DisplaySnapshot,
20772    ) -> Option<DisplayRow> {
20773        self.highlighted_rows
20774            .values()
20775            .flat_map(|highlighted_rows| highlighted_rows.iter())
20776            .filter_map(|highlight| {
20777                if highlight.options.autoscroll {
20778                    Some(highlight.range.start.to_display_point(snapshot).row())
20779                } else {
20780                    None
20781                }
20782            })
20783            .min()
20784    }
20785
20786    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20787        self.highlight_background::<SearchWithinRange>(
20788            ranges,
20789            |colors| colors.colors().editor_document_highlight_read_background,
20790            cx,
20791        )
20792    }
20793
20794    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20795        self.breadcrumb_header = Some(new_header);
20796    }
20797
20798    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20799        self.clear_background_highlights::<SearchWithinRange>(cx);
20800    }
20801
20802    pub fn highlight_background<T: 'static>(
20803        &mut self,
20804        ranges: &[Range<Anchor>],
20805        color_fetcher: fn(&Theme) -> Hsla,
20806        cx: &mut Context<Self>,
20807    ) {
20808        self.background_highlights.insert(
20809            HighlightKey::Type(TypeId::of::<T>()),
20810            (color_fetcher, Arc::from(ranges)),
20811        );
20812        self.scrollbar_marker_state.dirty = true;
20813        cx.notify();
20814    }
20815
20816    pub fn highlight_background_key<T: 'static>(
20817        &mut self,
20818        key: usize,
20819        ranges: &[Range<Anchor>],
20820        color_fetcher: fn(&Theme) -> Hsla,
20821        cx: &mut Context<Self>,
20822    ) {
20823        self.background_highlights.insert(
20824            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20825            (color_fetcher, Arc::from(ranges)),
20826        );
20827        self.scrollbar_marker_state.dirty = true;
20828        cx.notify();
20829    }
20830
20831    pub fn clear_background_highlights<T: 'static>(
20832        &mut self,
20833        cx: &mut Context<Self>,
20834    ) -> Option<BackgroundHighlight> {
20835        let text_highlights = self
20836            .background_highlights
20837            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20838        if !text_highlights.1.is_empty() {
20839            self.scrollbar_marker_state.dirty = true;
20840            cx.notify();
20841        }
20842        Some(text_highlights)
20843    }
20844
20845    pub fn highlight_gutter<T: 'static>(
20846        &mut self,
20847        ranges: impl Into<Vec<Range<Anchor>>>,
20848        color_fetcher: fn(&App) -> Hsla,
20849        cx: &mut Context<Self>,
20850    ) {
20851        self.gutter_highlights
20852            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20853        cx.notify();
20854    }
20855
20856    pub fn clear_gutter_highlights<T: 'static>(
20857        &mut self,
20858        cx: &mut Context<Self>,
20859    ) -> Option<GutterHighlight> {
20860        cx.notify();
20861        self.gutter_highlights.remove(&TypeId::of::<T>())
20862    }
20863
20864    pub fn insert_gutter_highlight<T: 'static>(
20865        &mut self,
20866        range: Range<Anchor>,
20867        color_fetcher: fn(&App) -> Hsla,
20868        cx: &mut Context<Self>,
20869    ) {
20870        let snapshot = self.buffer().read(cx).snapshot(cx);
20871        let mut highlights = self
20872            .gutter_highlights
20873            .remove(&TypeId::of::<T>())
20874            .map(|(_, highlights)| highlights)
20875            .unwrap_or_default();
20876        let ix = highlights.binary_search_by(|highlight| {
20877            Ordering::Equal
20878                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20879                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20880        });
20881        if let Err(ix) = ix {
20882            highlights.insert(ix, range);
20883        }
20884        self.gutter_highlights
20885            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20886    }
20887
20888    pub fn remove_gutter_highlights<T: 'static>(
20889        &mut self,
20890        ranges_to_remove: Vec<Range<Anchor>>,
20891        cx: &mut Context<Self>,
20892    ) {
20893        let snapshot = self.buffer().read(cx).snapshot(cx);
20894        let Some((color_fetcher, mut gutter_highlights)) =
20895            self.gutter_highlights.remove(&TypeId::of::<T>())
20896        else {
20897            return;
20898        };
20899        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20900        gutter_highlights.retain(|highlight| {
20901            while let Some(range_to_remove) = ranges_to_remove.peek() {
20902                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20903                    Ordering::Less | Ordering::Equal => {
20904                        ranges_to_remove.next();
20905                    }
20906                    Ordering::Greater => {
20907                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20908                            Ordering::Less | Ordering::Equal => {
20909                                return false;
20910                            }
20911                            Ordering::Greater => break,
20912                        }
20913                    }
20914                }
20915            }
20916
20917            true
20918        });
20919        self.gutter_highlights
20920            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20921    }
20922
20923    #[cfg(feature = "test-support")]
20924    pub fn all_text_highlights(
20925        &self,
20926        window: &mut Window,
20927        cx: &mut Context<Self>,
20928    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20929        let snapshot = self.snapshot(window, cx);
20930        self.display_map.update(cx, |display_map, _| {
20931            display_map
20932                .all_text_highlights()
20933                .map(|highlight| {
20934                    let (style, ranges) = highlight.as_ref();
20935                    (
20936                        *style,
20937                        ranges
20938                            .iter()
20939                            .map(|range| range.clone().to_display_points(&snapshot))
20940                            .collect(),
20941                    )
20942                })
20943                .collect()
20944        })
20945    }
20946
20947    #[cfg(feature = "test-support")]
20948    pub fn all_text_background_highlights(
20949        &self,
20950        window: &mut Window,
20951        cx: &mut Context<Self>,
20952    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20953        let snapshot = self.snapshot(window, cx);
20954        let buffer = &snapshot.buffer_snapshot();
20955        let start = buffer.anchor_before(MultiBufferOffset(0));
20956        let end = buffer.anchor_after(buffer.len());
20957        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20958    }
20959
20960    #[cfg(any(test, feature = "test-support"))]
20961    pub fn sorted_background_highlights_in_range(
20962        &self,
20963        search_range: Range<Anchor>,
20964        display_snapshot: &DisplaySnapshot,
20965        theme: &Theme,
20966    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20967        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20968        res.sort_by(|a, b| {
20969            a.0.start
20970                .cmp(&b.0.start)
20971                .then_with(|| a.0.end.cmp(&b.0.end))
20972                .then_with(|| a.1.cmp(&b.1))
20973        });
20974        res
20975    }
20976
20977    #[cfg(feature = "test-support")]
20978    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20979        let snapshot = self.buffer().read(cx).snapshot(cx);
20980
20981        let highlights = self
20982            .background_highlights
20983            .get(&HighlightKey::Type(TypeId::of::<
20984                items::BufferSearchHighlights,
20985            >()));
20986
20987        if let Some((_color, ranges)) = highlights {
20988            ranges
20989                .iter()
20990                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20991                .collect_vec()
20992        } else {
20993            vec![]
20994        }
20995    }
20996
20997    fn document_highlights_for_position<'a>(
20998        &'a self,
20999        position: Anchor,
21000        buffer: &'a MultiBufferSnapshot,
21001    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21002        let read_highlights = self
21003            .background_highlights
21004            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21005            .map(|h| &h.1);
21006        let write_highlights = self
21007            .background_highlights
21008            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21009            .map(|h| &h.1);
21010        let left_position = position.bias_left(buffer);
21011        let right_position = position.bias_right(buffer);
21012        read_highlights
21013            .into_iter()
21014            .chain(write_highlights)
21015            .flat_map(move |ranges| {
21016                let start_ix = match ranges.binary_search_by(|probe| {
21017                    let cmp = probe.end.cmp(&left_position, buffer);
21018                    if cmp.is_ge() {
21019                        Ordering::Greater
21020                    } else {
21021                        Ordering::Less
21022                    }
21023                }) {
21024                    Ok(i) | Err(i) => i,
21025                };
21026
21027                ranges[start_ix..]
21028                    .iter()
21029                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21030            })
21031    }
21032
21033    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21034        self.background_highlights
21035            .get(&HighlightKey::Type(TypeId::of::<T>()))
21036            .is_some_and(|(_, highlights)| !highlights.is_empty())
21037    }
21038
21039    /// Returns all background highlights for a given range.
21040    ///
21041    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21042    pub fn background_highlights_in_range(
21043        &self,
21044        search_range: Range<Anchor>,
21045        display_snapshot: &DisplaySnapshot,
21046        theme: &Theme,
21047    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21048        let mut results = Vec::new();
21049        for (color_fetcher, ranges) in self.background_highlights.values() {
21050            let color = color_fetcher(theme);
21051            let start_ix = match ranges.binary_search_by(|probe| {
21052                let cmp = probe
21053                    .end
21054                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21055                if cmp.is_gt() {
21056                    Ordering::Greater
21057                } else {
21058                    Ordering::Less
21059                }
21060            }) {
21061                Ok(i) | Err(i) => i,
21062            };
21063            for range in &ranges[start_ix..] {
21064                if range
21065                    .start
21066                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21067                    .is_ge()
21068                {
21069                    break;
21070                }
21071
21072                let start = range.start.to_display_point(display_snapshot);
21073                let end = range.end.to_display_point(display_snapshot);
21074                results.push((start..end, color))
21075            }
21076        }
21077        results
21078    }
21079
21080    pub fn gutter_highlights_in_range(
21081        &self,
21082        search_range: Range<Anchor>,
21083        display_snapshot: &DisplaySnapshot,
21084        cx: &App,
21085    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21086        let mut results = Vec::new();
21087        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21088            let color = color_fetcher(cx);
21089            let start_ix = match ranges.binary_search_by(|probe| {
21090                let cmp = probe
21091                    .end
21092                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21093                if cmp.is_gt() {
21094                    Ordering::Greater
21095                } else {
21096                    Ordering::Less
21097                }
21098            }) {
21099                Ok(i) | Err(i) => i,
21100            };
21101            for range in &ranges[start_ix..] {
21102                if range
21103                    .start
21104                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21105                    .is_ge()
21106                {
21107                    break;
21108                }
21109
21110                let start = range.start.to_display_point(display_snapshot);
21111                let end = range.end.to_display_point(display_snapshot);
21112                results.push((start..end, color))
21113            }
21114        }
21115        results
21116    }
21117
21118    /// Get the text ranges corresponding to the redaction query
21119    pub fn redacted_ranges(
21120        &self,
21121        search_range: Range<Anchor>,
21122        display_snapshot: &DisplaySnapshot,
21123        cx: &App,
21124    ) -> Vec<Range<DisplayPoint>> {
21125        display_snapshot
21126            .buffer_snapshot()
21127            .redacted_ranges(search_range, |file| {
21128                if let Some(file) = file {
21129                    file.is_private()
21130                        && EditorSettings::get(
21131                            Some(SettingsLocation {
21132                                worktree_id: file.worktree_id(cx),
21133                                path: file.path().as_ref(),
21134                            }),
21135                            cx,
21136                        )
21137                        .redact_private_values
21138                } else {
21139                    false
21140                }
21141            })
21142            .map(|range| {
21143                range.start.to_display_point(display_snapshot)
21144                    ..range.end.to_display_point(display_snapshot)
21145            })
21146            .collect()
21147    }
21148
21149    pub fn highlight_text_key<T: 'static>(
21150        &mut self,
21151        key: usize,
21152        ranges: Vec<Range<Anchor>>,
21153        style: HighlightStyle,
21154        merge: bool,
21155        cx: &mut Context<Self>,
21156    ) {
21157        self.display_map.update(cx, |map, cx| {
21158            map.highlight_text(
21159                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21160                ranges,
21161                style,
21162                merge,
21163                cx,
21164            );
21165        });
21166        cx.notify();
21167    }
21168
21169    pub fn highlight_text<T: 'static>(
21170        &mut self,
21171        ranges: Vec<Range<Anchor>>,
21172        style: HighlightStyle,
21173        cx: &mut Context<Self>,
21174    ) {
21175        self.display_map.update(cx, |map, cx| {
21176            map.highlight_text(
21177                HighlightKey::Type(TypeId::of::<T>()),
21178                ranges,
21179                style,
21180                false,
21181                cx,
21182            )
21183        });
21184        cx.notify();
21185    }
21186
21187    pub fn text_highlights<'a, T: 'static>(
21188        &'a self,
21189        cx: &'a App,
21190    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21191        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21192    }
21193
21194    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21195        let cleared = self
21196            .display_map
21197            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21198        if cleared {
21199            cx.notify();
21200        }
21201    }
21202
21203    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21204        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21205            && self.focus_handle.is_focused(window)
21206    }
21207
21208    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21209        self.show_cursor_when_unfocused = is_enabled;
21210        cx.notify();
21211    }
21212
21213    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21214        cx.notify();
21215    }
21216
21217    fn on_debug_session_event(
21218        &mut self,
21219        _session: Entity<Session>,
21220        event: &SessionEvent,
21221        cx: &mut Context<Self>,
21222    ) {
21223        if let SessionEvent::InvalidateInlineValue = event {
21224            self.refresh_inline_values(cx);
21225        }
21226    }
21227
21228    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21229        let Some(project) = self.project.clone() else {
21230            return;
21231        };
21232
21233        if !self.inline_value_cache.enabled {
21234            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21235            self.splice_inlays(&inlays, Vec::new(), cx);
21236            return;
21237        }
21238
21239        let current_execution_position = self
21240            .highlighted_rows
21241            .get(&TypeId::of::<ActiveDebugLine>())
21242            .and_then(|lines| lines.last().map(|line| line.range.end));
21243
21244        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21245            let inline_values = editor
21246                .update(cx, |editor, cx| {
21247                    let Some(current_execution_position) = current_execution_position else {
21248                        return Some(Task::ready(Ok(Vec::new())));
21249                    };
21250
21251                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21252                        let snapshot = buffer.snapshot(cx);
21253
21254                        let excerpt = snapshot.excerpt_containing(
21255                            current_execution_position..current_execution_position,
21256                        )?;
21257
21258                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21259                    })?;
21260
21261                    let range =
21262                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21263
21264                    project.inline_values(buffer, range, cx)
21265                })
21266                .ok()
21267                .flatten()?
21268                .await
21269                .context("refreshing debugger inlays")
21270                .log_err()?;
21271
21272            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21273
21274            for (buffer_id, inline_value) in inline_values
21275                .into_iter()
21276                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21277            {
21278                buffer_inline_values
21279                    .entry(buffer_id)
21280                    .or_default()
21281                    .push(inline_value);
21282            }
21283
21284            editor
21285                .update(cx, |editor, cx| {
21286                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21287                    let mut new_inlays = Vec::default();
21288
21289                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21290                        let buffer_id = buffer_snapshot.remote_id();
21291                        buffer_inline_values
21292                            .get(&buffer_id)
21293                            .into_iter()
21294                            .flatten()
21295                            .for_each(|hint| {
21296                                let inlay = Inlay::debugger(
21297                                    post_inc(&mut editor.next_inlay_id),
21298                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
21299                                    hint.text(),
21300                                );
21301                                if !inlay.text().chars().contains(&'\n') {
21302                                    new_inlays.push(inlay);
21303                                }
21304                            });
21305                    }
21306
21307                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21308                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21309
21310                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21311                })
21312                .ok()?;
21313            Some(())
21314        });
21315    }
21316
21317    fn on_buffer_event(
21318        &mut self,
21319        multibuffer: &Entity<MultiBuffer>,
21320        event: &multi_buffer::Event,
21321        window: &mut Window,
21322        cx: &mut Context<Self>,
21323    ) {
21324        match event {
21325            multi_buffer::Event::Edited { edited_buffer } => {
21326                self.scrollbar_marker_state.dirty = true;
21327                self.active_indent_guides_state.dirty = true;
21328                self.refresh_active_diagnostics(cx);
21329                self.refresh_code_actions(window, cx);
21330                self.refresh_single_line_folds(window, cx);
21331                self.refresh_matching_bracket_highlights(window, cx);
21332                if self.has_active_edit_prediction() {
21333                    self.update_visible_edit_prediction(window, cx);
21334                }
21335
21336                if let Some(buffer) = edited_buffer {
21337                    if buffer.read(cx).file().is_none() {
21338                        cx.emit(EditorEvent::TitleChanged);
21339                    }
21340
21341                    if self.project.is_some() {
21342                        let buffer_id = buffer.read(cx).remote_id();
21343                        self.register_buffer(buffer_id, cx);
21344                        self.update_lsp_data(Some(buffer_id), window, cx);
21345                        self.refresh_inlay_hints(
21346                            InlayHintRefreshReason::BufferEdited(buffer_id),
21347                            cx,
21348                        );
21349                    }
21350                }
21351
21352                cx.emit(EditorEvent::BufferEdited);
21353                cx.emit(SearchEvent::MatchesInvalidated);
21354
21355                let Some(project) = &self.project else { return };
21356                let (telemetry, is_via_ssh) = {
21357                    let project = project.read(cx);
21358                    let telemetry = project.client().telemetry().clone();
21359                    let is_via_ssh = project.is_via_remote_server();
21360                    (telemetry, is_via_ssh)
21361                };
21362                telemetry.log_edit_event("editor", is_via_ssh);
21363            }
21364            multi_buffer::Event::ExcerptsAdded {
21365                buffer,
21366                predecessor,
21367                excerpts,
21368            } => {
21369                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21370                let buffer_id = buffer.read(cx).remote_id();
21371                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21372                    && let Some(project) = &self.project
21373                {
21374                    update_uncommitted_diff_for_buffer(
21375                        cx.entity(),
21376                        project,
21377                        [buffer.clone()],
21378                        self.buffer.clone(),
21379                        cx,
21380                    )
21381                    .detach();
21382                }
21383                self.update_lsp_data(Some(buffer_id), window, cx);
21384                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21385                self.colorize_brackets(false, cx);
21386                cx.emit(EditorEvent::ExcerptsAdded {
21387                    buffer: buffer.clone(),
21388                    predecessor: *predecessor,
21389                    excerpts: excerpts.clone(),
21390                });
21391            }
21392            multi_buffer::Event::ExcerptsRemoved {
21393                ids,
21394                removed_buffer_ids,
21395            } => {
21396                if let Some(inlay_hints) = &mut self.inlay_hints {
21397                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21398                }
21399                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21400                for buffer_id in removed_buffer_ids {
21401                    self.registered_buffers.remove(buffer_id);
21402                }
21403                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21404                cx.emit(EditorEvent::ExcerptsRemoved {
21405                    ids: ids.clone(),
21406                    removed_buffer_ids: removed_buffer_ids.clone(),
21407                });
21408            }
21409            multi_buffer::Event::ExcerptsEdited {
21410                excerpt_ids,
21411                buffer_ids,
21412            } => {
21413                self.display_map.update(cx, |map, cx| {
21414                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21415                });
21416                cx.emit(EditorEvent::ExcerptsEdited {
21417                    ids: excerpt_ids.clone(),
21418                });
21419            }
21420            multi_buffer::Event::ExcerptsExpanded { ids } => {
21421                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21422                self.refresh_document_highlights(cx);
21423                for id in ids {
21424                    self.fetched_tree_sitter_chunks.remove(id);
21425                }
21426                self.colorize_brackets(false, cx);
21427                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21428            }
21429            multi_buffer::Event::Reparsed(buffer_id) => {
21430                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21431                self.refresh_selected_text_highlights(true, window, cx);
21432                self.colorize_brackets(true, cx);
21433                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21434
21435                cx.emit(EditorEvent::Reparsed(*buffer_id));
21436            }
21437            multi_buffer::Event::DiffHunksToggled => {
21438                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21439            }
21440            multi_buffer::Event::LanguageChanged(buffer_id) => {
21441                self.registered_buffers.remove(&buffer_id);
21442                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21443                cx.emit(EditorEvent::Reparsed(*buffer_id));
21444                cx.notify();
21445            }
21446            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21447            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21448            multi_buffer::Event::FileHandleChanged
21449            | multi_buffer::Event::Reloaded
21450            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21451            multi_buffer::Event::DiagnosticsUpdated => {
21452                self.update_diagnostics_state(window, cx);
21453            }
21454            _ => {}
21455        };
21456    }
21457
21458    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21459        if !self.diagnostics_enabled() {
21460            return;
21461        }
21462        self.refresh_active_diagnostics(cx);
21463        self.refresh_inline_diagnostics(true, window, cx);
21464        self.scrollbar_marker_state.dirty = true;
21465        cx.notify();
21466    }
21467
21468    pub fn start_temporary_diff_override(&mut self) {
21469        self.load_diff_task.take();
21470        self.temporary_diff_override = true;
21471    }
21472
21473    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21474        self.temporary_diff_override = false;
21475        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21476        self.buffer.update(cx, |buffer, cx| {
21477            buffer.set_all_diff_hunks_collapsed(cx);
21478        });
21479
21480        if let Some(project) = self.project.clone() {
21481            self.load_diff_task = Some(
21482                update_uncommitted_diff_for_buffer(
21483                    cx.entity(),
21484                    &project,
21485                    self.buffer.read(cx).all_buffers(),
21486                    self.buffer.clone(),
21487                    cx,
21488                )
21489                .shared(),
21490            );
21491        }
21492    }
21493
21494    fn on_display_map_changed(
21495        &mut self,
21496        _: Entity<DisplayMap>,
21497        _: &mut Window,
21498        cx: &mut Context<Self>,
21499    ) {
21500        cx.notify();
21501    }
21502
21503    fn fetch_accent_overrides(&self, cx: &App) -> Vec<SharedString> {
21504        if !self.mode.is_full() {
21505            return Vec::new();
21506        }
21507
21508        theme::ThemeSettings::get_global(cx)
21509            .theme_overrides
21510            .get(cx.theme().name.as_ref())
21511            .map(|theme_style| &theme_style.accents)
21512            .into_iter()
21513            .flatten()
21514            .flat_map(|accent| accent.0.clone())
21515            .collect()
21516    }
21517
21518    fn fetch_applicable_language_settings(
21519        &self,
21520        cx: &App,
21521    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
21522        if !self.mode.is_full() {
21523            return HashMap::default();
21524        }
21525
21526        self.buffer().read(cx).all_buffers().into_iter().fold(
21527            HashMap::default(),
21528            |mut acc, buffer| {
21529                let buffer = buffer.read(cx);
21530                let language = buffer.language().map(|language| language.name());
21531                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
21532                    let file = buffer.file();
21533                    v.insert(language_settings(language, file, cx).into_owned());
21534                }
21535                acc
21536            },
21537        )
21538    }
21539
21540    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21541        let new_language_settings = self.fetch_applicable_language_settings(cx);
21542        let language_settings_changed = new_language_settings != self.applicable_language_settings;
21543        self.applicable_language_settings = new_language_settings;
21544
21545        let new_accent_overrides = self.fetch_accent_overrides(cx);
21546        let accent_overrides_changed = new_accent_overrides != self.accent_overrides;
21547        self.accent_overrides = new_accent_overrides;
21548
21549        if self.diagnostics_enabled() {
21550            let new_severity = EditorSettings::get_global(cx)
21551                .diagnostics_max_severity
21552                .unwrap_or(DiagnosticSeverity::Hint);
21553            self.set_max_diagnostics_severity(new_severity, cx);
21554        }
21555        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21556        self.update_edit_prediction_settings(cx);
21557        self.refresh_edit_prediction(true, false, window, cx);
21558        self.refresh_inline_values(cx);
21559        self.refresh_inlay_hints(
21560            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21561                self.selections.newest_anchor().head(),
21562                &self.buffer.read(cx).snapshot(cx),
21563                cx,
21564            )),
21565            cx,
21566        );
21567
21568        let old_cursor_shape = self.cursor_shape;
21569        let old_show_breadcrumbs = self.show_breadcrumbs;
21570
21571        {
21572            let editor_settings = EditorSettings::get_global(cx);
21573            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21574            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21575            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21576            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21577        }
21578
21579        if old_cursor_shape != self.cursor_shape {
21580            cx.emit(EditorEvent::CursorShapeChanged);
21581        }
21582
21583        if old_show_breadcrumbs != self.show_breadcrumbs {
21584            cx.emit(EditorEvent::BreadcrumbsChanged);
21585        }
21586
21587        let project_settings = ProjectSettings::get_global(cx);
21588        self.buffer_serialization = self
21589            .should_serialize_buffer()
21590            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21591
21592        if self.mode.is_full() {
21593            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21594            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21595            if self.show_inline_diagnostics != show_inline_diagnostics {
21596                self.show_inline_diagnostics = show_inline_diagnostics;
21597                self.refresh_inline_diagnostics(false, window, cx);
21598            }
21599
21600            if self.git_blame_inline_enabled != inline_blame_enabled {
21601                self.toggle_git_blame_inline_internal(false, window, cx);
21602            }
21603
21604            let minimap_settings = EditorSettings::get_global(cx).minimap;
21605            if self.minimap_visibility != MinimapVisibility::Disabled {
21606                if self.minimap_visibility.settings_visibility()
21607                    != minimap_settings.minimap_enabled()
21608                {
21609                    self.set_minimap_visibility(
21610                        MinimapVisibility::for_mode(self.mode(), cx),
21611                        window,
21612                        cx,
21613                    );
21614                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21615                    minimap_entity.update(cx, |minimap_editor, cx| {
21616                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21617                    })
21618                }
21619            }
21620
21621            if language_settings_changed || accent_overrides_changed {
21622                self.colorize_brackets(true, cx);
21623            }
21624
21625            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21626                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21627            }) {
21628                if !inlay_splice.is_empty() {
21629                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21630                }
21631                self.refresh_colors_for_visible_range(None, window, cx);
21632            }
21633        }
21634
21635        cx.notify();
21636    }
21637
21638    pub fn set_searchable(&mut self, searchable: bool) {
21639        self.searchable = searchable;
21640    }
21641
21642    pub fn searchable(&self) -> bool {
21643        self.searchable
21644    }
21645
21646    pub fn open_excerpts_in_split(
21647        &mut self,
21648        _: &OpenExcerptsSplit,
21649        window: &mut Window,
21650        cx: &mut Context<Self>,
21651    ) {
21652        self.open_excerpts_common(None, true, window, cx)
21653    }
21654
21655    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21656        self.open_excerpts_common(None, false, window, cx)
21657    }
21658
21659    fn open_excerpts_common(
21660        &mut self,
21661        jump_data: Option<JumpData>,
21662        split: bool,
21663        window: &mut Window,
21664        cx: &mut Context<Self>,
21665    ) {
21666        let Some(workspace) = self.workspace() else {
21667            cx.propagate();
21668            return;
21669        };
21670
21671        if self.buffer.read(cx).is_singleton() {
21672            cx.propagate();
21673            return;
21674        }
21675
21676        let mut new_selections_by_buffer = HashMap::default();
21677        match &jump_data {
21678            Some(JumpData::MultiBufferPoint {
21679                excerpt_id,
21680                position,
21681                anchor,
21682                line_offset_from_top,
21683            }) => {
21684                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21685                if let Some(buffer) = multi_buffer_snapshot
21686                    .buffer_id_for_excerpt(*excerpt_id)
21687                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21688                {
21689                    let buffer_snapshot = buffer.read(cx).snapshot();
21690                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21691                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21692                    } else {
21693                        buffer_snapshot.clip_point(*position, Bias::Left)
21694                    };
21695                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21696                    new_selections_by_buffer.insert(
21697                        buffer,
21698                        (
21699                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
21700                            Some(*line_offset_from_top),
21701                        ),
21702                    );
21703                }
21704            }
21705            Some(JumpData::MultiBufferRow {
21706                row,
21707                line_offset_from_top,
21708            }) => {
21709                let point = MultiBufferPoint::new(row.0, 0);
21710                if let Some((buffer, buffer_point, _)) =
21711                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21712                {
21713                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21714                    new_selections_by_buffer
21715                        .entry(buffer)
21716                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21717                        .0
21718                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
21719                }
21720            }
21721            None => {
21722                let selections = self
21723                    .selections
21724                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
21725                let multi_buffer = self.buffer.read(cx);
21726                for selection in selections {
21727                    for (snapshot, range, _, anchor) in multi_buffer
21728                        .snapshot(cx)
21729                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21730                    {
21731                        if let Some(anchor) = anchor {
21732                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21733                            else {
21734                                continue;
21735                            };
21736                            let offset = text::ToOffset::to_offset(
21737                                &anchor.text_anchor,
21738                                &buffer_handle.read(cx).snapshot(),
21739                            );
21740                            let range = BufferOffset(offset)..BufferOffset(offset);
21741                            new_selections_by_buffer
21742                                .entry(buffer_handle)
21743                                .or_insert((Vec::new(), None))
21744                                .0
21745                                .push(range)
21746                        } else {
21747                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21748                            else {
21749                                continue;
21750                            };
21751                            new_selections_by_buffer
21752                                .entry(buffer_handle)
21753                                .or_insert((Vec::new(), None))
21754                                .0
21755                                .push(range)
21756                        }
21757                    }
21758                }
21759            }
21760        }
21761
21762        new_selections_by_buffer
21763            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21764
21765        if new_selections_by_buffer.is_empty() {
21766            return;
21767        }
21768
21769        // We defer the pane interaction because we ourselves are a workspace item
21770        // and activating a new item causes the pane to call a method on us reentrantly,
21771        // which panics if we're on the stack.
21772        window.defer(cx, move |window, cx| {
21773            workspace.update(cx, |workspace, cx| {
21774                let pane = if split {
21775                    workspace.adjacent_pane(window, cx)
21776                } else {
21777                    workspace.active_pane().clone()
21778                };
21779
21780                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21781                    let editor = buffer
21782                        .read(cx)
21783                        .file()
21784                        .is_none()
21785                        .then(|| {
21786                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21787                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21788                            // Instead, we try to activate the existing editor in the pane first.
21789                            let (editor, pane_item_index) =
21790                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21791                                    let editor = item.downcast::<Editor>()?;
21792                                    let singleton_buffer =
21793                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21794                                    if singleton_buffer == buffer {
21795                                        Some((editor, i))
21796                                    } else {
21797                                        None
21798                                    }
21799                                })?;
21800                            pane.update(cx, |pane, cx| {
21801                                pane.activate_item(pane_item_index, true, true, window, cx)
21802                            });
21803                            Some(editor)
21804                        })
21805                        .flatten()
21806                        .unwrap_or_else(|| {
21807                            workspace.open_project_item::<Self>(
21808                                pane.clone(),
21809                                buffer,
21810                                true,
21811                                true,
21812                                window,
21813                                cx,
21814                            )
21815                        });
21816
21817                    editor.update(cx, |editor, cx| {
21818                        let autoscroll = match scroll_offset {
21819                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21820                            None => Autoscroll::newest(),
21821                        };
21822                        let nav_history = editor.nav_history.take();
21823                        editor.change_selections(
21824                            SelectionEffects::scroll(autoscroll),
21825                            window,
21826                            cx,
21827                            |s| {
21828                                s.select_ranges(ranges.into_iter().map(|range| {
21829                                    // we checked that the editor is a singleton editor so the offsets are valid
21830                                    MultiBufferOffset(range.start.0)..MultiBufferOffset(range.end.0)
21831                                }));
21832                            },
21833                        );
21834                        editor.nav_history = nav_history;
21835                    });
21836                }
21837            })
21838        });
21839    }
21840
21841    // For now, don't allow opening excerpts in buffers that aren't backed by
21842    // regular project files.
21843    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21844        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21845    }
21846
21847    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
21848        let snapshot = self.buffer.read(cx).read(cx);
21849        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21850        Some(
21851            ranges
21852                .iter()
21853                .map(move |range| {
21854                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21855                })
21856                .collect(),
21857        )
21858    }
21859
21860    fn selection_replacement_ranges(
21861        &self,
21862        range: Range<MultiBufferOffsetUtf16>,
21863        cx: &mut App,
21864    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
21865        let selections = self
21866            .selections
21867            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
21868        let newest_selection = selections
21869            .iter()
21870            .max_by_key(|selection| selection.id)
21871            .unwrap();
21872        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
21873        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
21874        let snapshot = self.buffer.read(cx).read(cx);
21875        selections
21876            .into_iter()
21877            .map(|mut selection| {
21878                selection.start.0.0 =
21879                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
21880                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
21881                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21882                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21883            })
21884            .collect()
21885    }
21886
21887    fn report_editor_event(
21888        &self,
21889        reported_event: ReportEditorEvent,
21890        file_extension: Option<String>,
21891        cx: &App,
21892    ) {
21893        if cfg!(any(test, feature = "test-support")) {
21894            return;
21895        }
21896
21897        let Some(project) = &self.project else { return };
21898
21899        // If None, we are in a file without an extension
21900        let file = self
21901            .buffer
21902            .read(cx)
21903            .as_singleton()
21904            .and_then(|b| b.read(cx).file());
21905        let file_extension = file_extension.or(file
21906            .as_ref()
21907            .and_then(|file| Path::new(file.file_name(cx)).extension())
21908            .and_then(|e| e.to_str())
21909            .map(|a| a.to_string()));
21910
21911        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
21912            .map(|vim_mode| vim_mode.0)
21913            .unwrap_or(false);
21914
21915        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21916        let copilot_enabled = edit_predictions_provider
21917            == language::language_settings::EditPredictionProvider::Copilot;
21918        let copilot_enabled_for_language = self
21919            .buffer
21920            .read(cx)
21921            .language_settings(cx)
21922            .show_edit_predictions;
21923
21924        let project = project.read(cx);
21925        let event_type = reported_event.event_type();
21926
21927        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21928            telemetry::event!(
21929                event_type,
21930                type = if auto_saved {"autosave"} else {"manual"},
21931                file_extension,
21932                vim_mode,
21933                copilot_enabled,
21934                copilot_enabled_for_language,
21935                edit_predictions_provider,
21936                is_via_ssh = project.is_via_remote_server(),
21937            );
21938        } else {
21939            telemetry::event!(
21940                event_type,
21941                file_extension,
21942                vim_mode,
21943                copilot_enabled,
21944                copilot_enabled_for_language,
21945                edit_predictions_provider,
21946                is_via_ssh = project.is_via_remote_server(),
21947            );
21948        };
21949    }
21950
21951    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21952    /// with each line being an array of {text, highlight} objects.
21953    fn copy_highlight_json(
21954        &mut self,
21955        _: &CopyHighlightJson,
21956        window: &mut Window,
21957        cx: &mut Context<Self>,
21958    ) {
21959        #[derive(Serialize)]
21960        struct Chunk<'a> {
21961            text: String,
21962            highlight: Option<&'a str>,
21963        }
21964
21965        let snapshot = self.buffer.read(cx).snapshot(cx);
21966        let range = self
21967            .selected_text_range(false, window, cx)
21968            .and_then(|selection| {
21969                if selection.range.is_empty() {
21970                    None
21971                } else {
21972                    Some(
21973                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
21974                            selection.range.start,
21975                        )))
21976                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
21977                                selection.range.end,
21978                            ))),
21979                    )
21980                }
21981            })
21982            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
21983
21984        let chunks = snapshot.chunks(range, true);
21985        let mut lines = Vec::new();
21986        let mut line: VecDeque<Chunk> = VecDeque::new();
21987
21988        let Some(style) = self.style.as_ref() else {
21989            return;
21990        };
21991
21992        for chunk in chunks {
21993            let highlight = chunk
21994                .syntax_highlight_id
21995                .and_then(|id| id.name(&style.syntax));
21996            let mut chunk_lines = chunk.text.split('\n').peekable();
21997            while let Some(text) = chunk_lines.next() {
21998                let mut merged_with_last_token = false;
21999                if let Some(last_token) = line.back_mut()
22000                    && last_token.highlight == highlight
22001                {
22002                    last_token.text.push_str(text);
22003                    merged_with_last_token = true;
22004                }
22005
22006                if !merged_with_last_token {
22007                    line.push_back(Chunk {
22008                        text: text.into(),
22009                        highlight,
22010                    });
22011                }
22012
22013                if chunk_lines.peek().is_some() {
22014                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22015                        line.pop_front();
22016                    }
22017                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22018                        line.pop_back();
22019                    }
22020
22021                    lines.push(mem::take(&mut line));
22022                }
22023            }
22024        }
22025
22026        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22027            return;
22028        };
22029        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22030    }
22031
22032    pub fn open_context_menu(
22033        &mut self,
22034        _: &OpenContextMenu,
22035        window: &mut Window,
22036        cx: &mut Context<Self>,
22037    ) {
22038        self.request_autoscroll(Autoscroll::newest(), cx);
22039        let position = self
22040            .selections
22041            .newest_display(&self.display_snapshot(cx))
22042            .start;
22043        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22044    }
22045
22046    pub fn replay_insert_event(
22047        &mut self,
22048        text: &str,
22049        relative_utf16_range: Option<Range<isize>>,
22050        window: &mut Window,
22051        cx: &mut Context<Self>,
22052    ) {
22053        if !self.input_enabled {
22054            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22055            return;
22056        }
22057        if let Some(relative_utf16_range) = relative_utf16_range {
22058            let selections = self
22059                .selections
22060                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22061            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22062                let new_ranges = selections.into_iter().map(|range| {
22063                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22064                        range
22065                            .head()
22066                            .0
22067                            .0
22068                            .saturating_add_signed(relative_utf16_range.start),
22069                    ));
22070                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22071                        range
22072                            .head()
22073                            .0
22074                            .0
22075                            .saturating_add_signed(relative_utf16_range.end),
22076                    ));
22077                    start..end
22078                });
22079                s.select_ranges(new_ranges);
22080            });
22081        }
22082
22083        self.handle_input(text, window, cx);
22084    }
22085
22086    pub fn is_focused(&self, window: &Window) -> bool {
22087        self.focus_handle.is_focused(window)
22088    }
22089
22090    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22091        cx.emit(EditorEvent::Focused);
22092
22093        if let Some(descendant) = self
22094            .last_focused_descendant
22095            .take()
22096            .and_then(|descendant| descendant.upgrade())
22097        {
22098            window.focus(&descendant);
22099        } else {
22100            if let Some(blame) = self.blame.as_ref() {
22101                blame.update(cx, GitBlame::focus)
22102            }
22103
22104            self.blink_manager.update(cx, BlinkManager::enable);
22105            self.show_cursor_names(window, cx);
22106            self.buffer.update(cx, |buffer, cx| {
22107                buffer.finalize_last_transaction(cx);
22108                if self.leader_id.is_none() {
22109                    buffer.set_active_selections(
22110                        &self.selections.disjoint_anchors_arc(),
22111                        self.selections.line_mode(),
22112                        self.cursor_shape,
22113                        cx,
22114                    );
22115                }
22116            });
22117        }
22118    }
22119
22120    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22121        cx.emit(EditorEvent::FocusedIn)
22122    }
22123
22124    fn handle_focus_out(
22125        &mut self,
22126        event: FocusOutEvent,
22127        _window: &mut Window,
22128        cx: &mut Context<Self>,
22129    ) {
22130        if event.blurred != self.focus_handle {
22131            self.last_focused_descendant = Some(event.blurred);
22132        }
22133        self.selection_drag_state = SelectionDragState::None;
22134        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22135    }
22136
22137    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22138        self.blink_manager.update(cx, BlinkManager::disable);
22139        self.buffer
22140            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22141
22142        if let Some(blame) = self.blame.as_ref() {
22143            blame.update(cx, GitBlame::blur)
22144        }
22145        if !self.hover_state.focused(window, cx) {
22146            hide_hover(self, cx);
22147        }
22148        if !self
22149            .context_menu
22150            .borrow()
22151            .as_ref()
22152            .is_some_and(|context_menu| context_menu.focused(window, cx))
22153        {
22154            self.hide_context_menu(window, cx);
22155        }
22156        self.take_active_edit_prediction(cx);
22157        cx.emit(EditorEvent::Blurred);
22158        cx.notify();
22159    }
22160
22161    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22162        let mut pending: String = window
22163            .pending_input_keystrokes()
22164            .into_iter()
22165            .flatten()
22166            .filter_map(|keystroke| keystroke.key_char.clone())
22167            .collect();
22168
22169        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22170            pending = "".to_string();
22171        }
22172
22173        let existing_pending = self
22174            .text_highlights::<PendingInput>(cx)
22175            .map(|(_, ranges)| ranges.to_vec());
22176        if existing_pending.is_none() && pending.is_empty() {
22177            return;
22178        }
22179        let transaction =
22180            self.transact(window, cx, |this, window, cx| {
22181                let selections = this
22182                    .selections
22183                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22184                let edits = selections
22185                    .iter()
22186                    .map(|selection| (selection.end..selection.end, pending.clone()));
22187                this.edit(edits, cx);
22188                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22189                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22190                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22191                    }));
22192                });
22193                if let Some(existing_ranges) = existing_pending {
22194                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22195                    this.edit(edits, cx);
22196                }
22197            });
22198
22199        let snapshot = self.snapshot(window, cx);
22200        let ranges = self
22201            .selections
22202            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22203            .into_iter()
22204            .map(|selection| {
22205                snapshot.buffer_snapshot().anchor_after(selection.end)
22206                    ..snapshot
22207                        .buffer_snapshot()
22208                        .anchor_before(selection.end + pending.len())
22209            })
22210            .collect();
22211
22212        if pending.is_empty() {
22213            self.clear_highlights::<PendingInput>(cx);
22214        } else {
22215            self.highlight_text::<PendingInput>(
22216                ranges,
22217                HighlightStyle {
22218                    underline: Some(UnderlineStyle {
22219                        thickness: px(1.),
22220                        color: None,
22221                        wavy: false,
22222                    }),
22223                    ..Default::default()
22224                },
22225                cx,
22226            );
22227        }
22228
22229        self.ime_transaction = self.ime_transaction.or(transaction);
22230        if let Some(transaction) = self.ime_transaction {
22231            self.buffer.update(cx, |buffer, cx| {
22232                buffer.group_until_transaction(transaction, cx);
22233            });
22234        }
22235
22236        if self.text_highlights::<PendingInput>(cx).is_none() {
22237            self.ime_transaction.take();
22238        }
22239    }
22240
22241    pub fn register_action_renderer(
22242        &mut self,
22243        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22244    ) -> Subscription {
22245        let id = self.next_editor_action_id.post_inc();
22246        self.editor_actions
22247            .borrow_mut()
22248            .insert(id, Box::new(listener));
22249
22250        let editor_actions = self.editor_actions.clone();
22251        Subscription::new(move || {
22252            editor_actions.borrow_mut().remove(&id);
22253        })
22254    }
22255
22256    pub fn register_action<A: Action>(
22257        &mut self,
22258        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22259    ) -> Subscription {
22260        let id = self.next_editor_action_id.post_inc();
22261        let listener = Arc::new(listener);
22262        self.editor_actions.borrow_mut().insert(
22263            id,
22264            Box::new(move |_, window, _| {
22265                let listener = listener.clone();
22266                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22267                    let action = action.downcast_ref().unwrap();
22268                    if phase == DispatchPhase::Bubble {
22269                        listener(action, window, cx)
22270                    }
22271                })
22272            }),
22273        );
22274
22275        let editor_actions = self.editor_actions.clone();
22276        Subscription::new(move || {
22277            editor_actions.borrow_mut().remove(&id);
22278        })
22279    }
22280
22281    pub fn file_header_size(&self) -> u32 {
22282        FILE_HEADER_HEIGHT
22283    }
22284
22285    pub fn restore(
22286        &mut self,
22287        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22288        window: &mut Window,
22289        cx: &mut Context<Self>,
22290    ) {
22291        let workspace = self.workspace();
22292        let project = self.project();
22293        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22294            let mut tasks = Vec::new();
22295            for (buffer_id, changes) in revert_changes {
22296                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22297                    buffer.update(cx, |buffer, cx| {
22298                        buffer.edit(
22299                            changes
22300                                .into_iter()
22301                                .map(|(range, text)| (range, text.to_string())),
22302                            None,
22303                            cx,
22304                        );
22305                    });
22306
22307                    if let Some(project) =
22308                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22309                    {
22310                        project.update(cx, |project, cx| {
22311                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22312                        })
22313                    }
22314                }
22315            }
22316            tasks
22317        });
22318        cx.spawn_in(window, async move |_, cx| {
22319            for (buffer, task) in save_tasks {
22320                let result = task.await;
22321                if result.is_err() {
22322                    let Some(path) = buffer
22323                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22324                        .ok()
22325                    else {
22326                        continue;
22327                    };
22328                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22329                        let Some(task) = cx
22330                            .update_window_entity(workspace, |workspace, window, cx| {
22331                                workspace
22332                                    .open_path_preview(path, None, false, false, false, window, cx)
22333                            })
22334                            .ok()
22335                        else {
22336                            continue;
22337                        };
22338                        task.await.log_err();
22339                    }
22340                }
22341            }
22342        })
22343        .detach();
22344        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22345            selections.refresh()
22346        });
22347    }
22348
22349    pub fn to_pixel_point(
22350        &self,
22351        source: multi_buffer::Anchor,
22352        editor_snapshot: &EditorSnapshot,
22353        window: &mut Window,
22354    ) -> Option<gpui::Point<Pixels>> {
22355        let source_point = source.to_display_point(editor_snapshot);
22356        self.display_to_pixel_point(source_point, editor_snapshot, window)
22357    }
22358
22359    pub fn display_to_pixel_point(
22360        &self,
22361        source: DisplayPoint,
22362        editor_snapshot: &EditorSnapshot,
22363        window: &mut Window,
22364    ) -> Option<gpui::Point<Pixels>> {
22365        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22366        let text_layout_details = self.text_layout_details(window);
22367        let scroll_top = text_layout_details
22368            .scroll_anchor
22369            .scroll_position(editor_snapshot)
22370            .y;
22371
22372        if source.row().as_f64() < scroll_top.floor() {
22373            return None;
22374        }
22375        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22376        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22377        Some(gpui::Point::new(source_x, source_y))
22378    }
22379
22380    pub fn has_visible_completions_menu(&self) -> bool {
22381        !self.edit_prediction_preview_is_active()
22382            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22383                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22384            })
22385    }
22386
22387    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22388        if self.mode.is_minimap() {
22389            return;
22390        }
22391        self.addons
22392            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22393    }
22394
22395    pub fn unregister_addon<T: Addon>(&mut self) {
22396        self.addons.remove(&std::any::TypeId::of::<T>());
22397    }
22398
22399    pub fn addon<T: Addon>(&self) -> Option<&T> {
22400        let type_id = std::any::TypeId::of::<T>();
22401        self.addons
22402            .get(&type_id)
22403            .and_then(|item| item.to_any().downcast_ref::<T>())
22404    }
22405
22406    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22407        let type_id = std::any::TypeId::of::<T>();
22408        self.addons
22409            .get_mut(&type_id)
22410            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22411    }
22412
22413    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22414        let text_layout_details = self.text_layout_details(window);
22415        let style = &text_layout_details.editor_style;
22416        let font_id = window.text_system().resolve_font(&style.text.font());
22417        let font_size = style.text.font_size.to_pixels(window.rem_size());
22418        let line_height = style.text.line_height_in_pixels(window.rem_size());
22419        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22420        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22421
22422        CharacterDimensions {
22423            em_width,
22424            em_advance,
22425            line_height,
22426        }
22427    }
22428
22429    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22430        self.load_diff_task.clone()
22431    }
22432
22433    fn read_metadata_from_db(
22434        &mut self,
22435        item_id: u64,
22436        workspace_id: WorkspaceId,
22437        window: &mut Window,
22438        cx: &mut Context<Editor>,
22439    ) {
22440        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22441            && !self.mode.is_minimap()
22442            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22443        {
22444            let buffer_snapshot = OnceCell::new();
22445
22446            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22447                && !folds.is_empty()
22448            {
22449                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22450                self.fold_ranges(
22451                    folds
22452                        .into_iter()
22453                        .map(|(start, end)| {
22454                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22455                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22456                        })
22457                        .collect(),
22458                    false,
22459                    window,
22460                    cx,
22461                );
22462            }
22463
22464            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22465                && !selections.is_empty()
22466            {
22467                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22468                // skip adding the initial selection to selection history
22469                self.selection_history.mode = SelectionHistoryMode::Skipping;
22470                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22471                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22472                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22473                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22474                    }));
22475                });
22476                self.selection_history.mode = SelectionHistoryMode::Normal;
22477            };
22478        }
22479
22480        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22481    }
22482
22483    fn update_lsp_data(
22484        &mut self,
22485        for_buffer: Option<BufferId>,
22486        window: &mut Window,
22487        cx: &mut Context<'_, Self>,
22488    ) {
22489        self.pull_diagnostics(for_buffer, window, cx);
22490        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22491    }
22492
22493    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22494        if self.ignore_lsp_data() {
22495            return;
22496        }
22497        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22498            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22499        }
22500    }
22501
22502    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22503        if self.ignore_lsp_data() {
22504            return;
22505        }
22506
22507        if !self.registered_buffers.contains_key(&buffer_id)
22508            && let Some(project) = self.project.as_ref()
22509        {
22510            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22511                project.update(cx, |project, cx| {
22512                    self.registered_buffers.insert(
22513                        buffer_id,
22514                        project.register_buffer_with_language_servers(&buffer, cx),
22515                    );
22516                });
22517            } else {
22518                self.registered_buffers.remove(&buffer_id);
22519            }
22520        }
22521    }
22522
22523    fn ignore_lsp_data(&self) -> bool {
22524        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22525        // skip any LSP updates for it.
22526        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22527    }
22528}
22529
22530fn edit_for_markdown_paste<'a>(
22531    buffer: &MultiBufferSnapshot,
22532    range: Range<MultiBufferOffset>,
22533    to_insert: &'a str,
22534    url: Option<url::Url>,
22535) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
22536    if url.is_none() {
22537        return (range, Cow::Borrowed(to_insert));
22538    };
22539
22540    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22541
22542    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22543        Cow::Borrowed(to_insert)
22544    } else {
22545        Cow::Owned(format!("[{old_text}]({to_insert})"))
22546    };
22547    (range, new_text)
22548}
22549
22550fn process_completion_for_edit(
22551    completion: &Completion,
22552    intent: CompletionIntent,
22553    buffer: &Entity<Buffer>,
22554    cursor_position: &text::Anchor,
22555    cx: &mut Context<Editor>,
22556) -> CompletionEdit {
22557    let buffer = buffer.read(cx);
22558    let buffer_snapshot = buffer.snapshot();
22559    let (snippet, new_text) = if completion.is_snippet() {
22560        let mut snippet_source = completion.new_text.clone();
22561        // Workaround for typescript language server issues so that methods don't expand within
22562        // strings and functions with type expressions. The previous point is used because the query
22563        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22564        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22565        let previous_point = if previous_point.column > 0 {
22566            cursor_position.to_previous_offset(&buffer_snapshot)
22567        } else {
22568            cursor_position.to_offset(&buffer_snapshot)
22569        };
22570        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22571            && scope.prefers_label_for_snippet_in_completion()
22572            && let Some(label) = completion.label()
22573            && matches!(
22574                completion.kind(),
22575                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22576            )
22577        {
22578            snippet_source = label;
22579        }
22580        match Snippet::parse(&snippet_source).log_err() {
22581            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22582            None => (None, completion.new_text.clone()),
22583        }
22584    } else {
22585        (None, completion.new_text.clone())
22586    };
22587
22588    let mut range_to_replace = {
22589        let replace_range = &completion.replace_range;
22590        if let CompletionSource::Lsp {
22591            insert_range: Some(insert_range),
22592            ..
22593        } = &completion.source
22594        {
22595            debug_assert_eq!(
22596                insert_range.start, replace_range.start,
22597                "insert_range and replace_range should start at the same position"
22598            );
22599            debug_assert!(
22600                insert_range
22601                    .start
22602                    .cmp(cursor_position, &buffer_snapshot)
22603                    .is_le(),
22604                "insert_range should start before or at cursor position"
22605            );
22606            debug_assert!(
22607                replace_range
22608                    .start
22609                    .cmp(cursor_position, &buffer_snapshot)
22610                    .is_le(),
22611                "replace_range should start before or at cursor position"
22612            );
22613
22614            let should_replace = match intent {
22615                CompletionIntent::CompleteWithInsert => false,
22616                CompletionIntent::CompleteWithReplace => true,
22617                CompletionIntent::Complete | CompletionIntent::Compose => {
22618                    let insert_mode =
22619                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22620                            .completions
22621                            .lsp_insert_mode;
22622                    match insert_mode {
22623                        LspInsertMode::Insert => false,
22624                        LspInsertMode::Replace => true,
22625                        LspInsertMode::ReplaceSubsequence => {
22626                            let mut text_to_replace = buffer.chars_for_range(
22627                                buffer.anchor_before(replace_range.start)
22628                                    ..buffer.anchor_after(replace_range.end),
22629                            );
22630                            let mut current_needle = text_to_replace.next();
22631                            for haystack_ch in completion.label.text.chars() {
22632                                if let Some(needle_ch) = current_needle
22633                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22634                                {
22635                                    current_needle = text_to_replace.next();
22636                                }
22637                            }
22638                            current_needle.is_none()
22639                        }
22640                        LspInsertMode::ReplaceSuffix => {
22641                            if replace_range
22642                                .end
22643                                .cmp(cursor_position, &buffer_snapshot)
22644                                .is_gt()
22645                            {
22646                                let range_after_cursor = *cursor_position..replace_range.end;
22647                                let text_after_cursor = buffer
22648                                    .text_for_range(
22649                                        buffer.anchor_before(range_after_cursor.start)
22650                                            ..buffer.anchor_after(range_after_cursor.end),
22651                                    )
22652                                    .collect::<String>()
22653                                    .to_ascii_lowercase();
22654                                completion
22655                                    .label
22656                                    .text
22657                                    .to_ascii_lowercase()
22658                                    .ends_with(&text_after_cursor)
22659                            } else {
22660                                true
22661                            }
22662                        }
22663                    }
22664                }
22665            };
22666
22667            if should_replace {
22668                replace_range.clone()
22669            } else {
22670                insert_range.clone()
22671            }
22672        } else {
22673            replace_range.clone()
22674        }
22675    };
22676
22677    if range_to_replace
22678        .end
22679        .cmp(cursor_position, &buffer_snapshot)
22680        .is_lt()
22681    {
22682        range_to_replace.end = *cursor_position;
22683    }
22684
22685    let replace_range = range_to_replace.to_offset(buffer);
22686    CompletionEdit {
22687        new_text,
22688        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
22689        snippet,
22690    }
22691}
22692
22693struct CompletionEdit {
22694    new_text: String,
22695    replace_range: Range<BufferOffset>,
22696    snippet: Option<Snippet>,
22697}
22698
22699fn insert_extra_newline_brackets(
22700    buffer: &MultiBufferSnapshot,
22701    range: Range<MultiBufferOffset>,
22702    language: &language::LanguageScope,
22703) -> bool {
22704    let leading_whitespace_len = buffer
22705        .reversed_chars_at(range.start)
22706        .take_while(|c| c.is_whitespace() && *c != '\n')
22707        .map(|c| c.len_utf8())
22708        .sum::<usize>();
22709    let trailing_whitespace_len = buffer
22710        .chars_at(range.end)
22711        .take_while(|c| c.is_whitespace() && *c != '\n')
22712        .map(|c| c.len_utf8())
22713        .sum::<usize>();
22714    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22715
22716    language.brackets().any(|(pair, enabled)| {
22717        let pair_start = pair.start.trim_end();
22718        let pair_end = pair.end.trim_start();
22719
22720        enabled
22721            && pair.newline
22722            && buffer.contains_str_at(range.end, pair_end)
22723            && buffer.contains_str_at(
22724                range.start.saturating_sub_usize(pair_start.len()),
22725                pair_start,
22726            )
22727    })
22728}
22729
22730fn insert_extra_newline_tree_sitter(
22731    buffer: &MultiBufferSnapshot,
22732    range: Range<MultiBufferOffset>,
22733) -> bool {
22734    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22735        [(buffer, range, _)] => (*buffer, range.clone()),
22736        _ => return false,
22737    };
22738    let pair = {
22739        let mut result: Option<BracketMatch<usize>> = None;
22740
22741        for pair in buffer
22742            .all_bracket_ranges(range.start.0..range.end.0)
22743            .filter(move |pair| {
22744                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
22745            })
22746        {
22747            let len = pair.close_range.end - pair.open_range.start;
22748
22749            if let Some(existing) = &result {
22750                let existing_len = existing.close_range.end - existing.open_range.start;
22751                if len > existing_len {
22752                    continue;
22753                }
22754            }
22755
22756            result = Some(pair);
22757        }
22758
22759        result
22760    };
22761    let Some(pair) = pair else {
22762        return false;
22763    };
22764    pair.newline_only
22765        && buffer
22766            .chars_for_range(pair.open_range.end..range.start.0)
22767            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
22768            .all(|c| c.is_whitespace() && c != '\n')
22769}
22770
22771fn update_uncommitted_diff_for_buffer(
22772    editor: Entity<Editor>,
22773    project: &Entity<Project>,
22774    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22775    buffer: Entity<MultiBuffer>,
22776    cx: &mut App,
22777) -> Task<()> {
22778    let mut tasks = Vec::new();
22779    project.update(cx, |project, cx| {
22780        for buffer in buffers {
22781            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22782                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22783            }
22784        }
22785    });
22786    cx.spawn(async move |cx| {
22787        let diffs = future::join_all(tasks).await;
22788        if editor
22789            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22790            .unwrap_or(false)
22791        {
22792            return;
22793        }
22794
22795        buffer
22796            .update(cx, |buffer, cx| {
22797                for diff in diffs.into_iter().flatten() {
22798                    buffer.add_diff(diff, cx);
22799                }
22800            })
22801            .ok();
22802    })
22803}
22804
22805fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22806    let tab_size = tab_size.get() as usize;
22807    let mut width = offset;
22808
22809    for ch in text.chars() {
22810        width += if ch == '\t' {
22811            tab_size - (width % tab_size)
22812        } else {
22813            1
22814        };
22815    }
22816
22817    width - offset
22818}
22819
22820#[cfg(test)]
22821mod tests {
22822    use super::*;
22823
22824    #[test]
22825    fn test_string_size_with_expanded_tabs() {
22826        let nz = |val| NonZeroU32::new(val).unwrap();
22827        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22828        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22829        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22830        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22831        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22832        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22833        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22834        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22835    }
22836}
22837
22838/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22839struct WordBreakingTokenizer<'a> {
22840    input: &'a str,
22841}
22842
22843impl<'a> WordBreakingTokenizer<'a> {
22844    fn new(input: &'a str) -> Self {
22845        Self { input }
22846    }
22847}
22848
22849fn is_char_ideographic(ch: char) -> bool {
22850    use unicode_script::Script::*;
22851    use unicode_script::UnicodeScript;
22852    matches!(ch.script(), Han | Tangut | Yi)
22853}
22854
22855fn is_grapheme_ideographic(text: &str) -> bool {
22856    text.chars().any(is_char_ideographic)
22857}
22858
22859fn is_grapheme_whitespace(text: &str) -> bool {
22860    text.chars().any(|x| x.is_whitespace())
22861}
22862
22863fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22864    text.chars()
22865        .next()
22866        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22867}
22868
22869#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22870enum WordBreakToken<'a> {
22871    Word { token: &'a str, grapheme_len: usize },
22872    InlineWhitespace { token: &'a str, grapheme_len: usize },
22873    Newline,
22874}
22875
22876impl<'a> Iterator for WordBreakingTokenizer<'a> {
22877    /// Yields a span, the count of graphemes in the token, and whether it was
22878    /// whitespace. Note that it also breaks at word boundaries.
22879    type Item = WordBreakToken<'a>;
22880
22881    fn next(&mut self) -> Option<Self::Item> {
22882        use unicode_segmentation::UnicodeSegmentation;
22883        if self.input.is_empty() {
22884            return None;
22885        }
22886
22887        let mut iter = self.input.graphemes(true).peekable();
22888        let mut offset = 0;
22889        let mut grapheme_len = 0;
22890        if let Some(first_grapheme) = iter.next() {
22891            let is_newline = first_grapheme == "\n";
22892            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22893            offset += first_grapheme.len();
22894            grapheme_len += 1;
22895            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22896                if let Some(grapheme) = iter.peek().copied()
22897                    && should_stay_with_preceding_ideograph(grapheme)
22898                {
22899                    offset += grapheme.len();
22900                    grapheme_len += 1;
22901                }
22902            } else {
22903                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22904                let mut next_word_bound = words.peek().copied();
22905                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22906                    next_word_bound = words.next();
22907                }
22908                while let Some(grapheme) = iter.peek().copied() {
22909                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22910                        break;
22911                    };
22912                    if is_grapheme_whitespace(grapheme) != is_whitespace
22913                        || (grapheme == "\n") != is_newline
22914                    {
22915                        break;
22916                    };
22917                    offset += grapheme.len();
22918                    grapheme_len += 1;
22919                    iter.next();
22920                }
22921            }
22922            let token = &self.input[..offset];
22923            self.input = &self.input[offset..];
22924            if token == "\n" {
22925                Some(WordBreakToken::Newline)
22926            } else if is_whitespace {
22927                Some(WordBreakToken::InlineWhitespace {
22928                    token,
22929                    grapheme_len,
22930                })
22931            } else {
22932                Some(WordBreakToken::Word {
22933                    token,
22934                    grapheme_len,
22935                })
22936            }
22937        } else {
22938            None
22939        }
22940    }
22941}
22942
22943#[test]
22944fn test_word_breaking_tokenizer() {
22945    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22946        ("", &[]),
22947        ("  ", &[whitespace("  ", 2)]),
22948        ("Ʒ", &[word("Ʒ", 1)]),
22949        ("Ǽ", &[word("Ǽ", 1)]),
22950        ("", &[word("", 1)]),
22951        ("⋑⋑", &[word("⋑⋑", 2)]),
22952        (
22953            "原理,进而",
22954            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22955        ),
22956        (
22957            "hello world",
22958            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22959        ),
22960        (
22961            "hello, world",
22962            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22963        ),
22964        (
22965            "  hello world",
22966            &[
22967                whitespace("  ", 2),
22968                word("hello", 5),
22969                whitespace(" ", 1),
22970                word("world", 5),
22971            ],
22972        ),
22973        (
22974            "这是什么 \n 钢笔",
22975            &[
22976                word("", 1),
22977                word("", 1),
22978                word("", 1),
22979                word("", 1),
22980                whitespace(" ", 1),
22981                newline(),
22982                whitespace(" ", 1),
22983                word("", 1),
22984                word("", 1),
22985            ],
22986        ),
22987        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22988    ];
22989
22990    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22991        WordBreakToken::Word {
22992            token,
22993            grapheme_len,
22994        }
22995    }
22996
22997    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22998        WordBreakToken::InlineWhitespace {
22999            token,
23000            grapheme_len,
23001        }
23002    }
23003
23004    fn newline() -> WordBreakToken<'static> {
23005        WordBreakToken::Newline
23006    }
23007
23008    for (input, result) in tests {
23009        assert_eq!(
23010            WordBreakingTokenizer::new(input)
23011                .collect::<Vec<_>>()
23012                .as_slice(),
23013            *result,
23014        );
23015    }
23016}
23017
23018fn wrap_with_prefix(
23019    first_line_prefix: String,
23020    subsequent_lines_prefix: String,
23021    unwrapped_text: String,
23022    wrap_column: usize,
23023    tab_size: NonZeroU32,
23024    preserve_existing_whitespace: bool,
23025) -> String {
23026    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23027    let subsequent_lines_prefix_len =
23028        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23029    let mut wrapped_text = String::new();
23030    let mut current_line = first_line_prefix;
23031    let mut is_first_line = true;
23032
23033    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23034    let mut current_line_len = first_line_prefix_len;
23035    let mut in_whitespace = false;
23036    for token in tokenizer {
23037        let have_preceding_whitespace = in_whitespace;
23038        match token {
23039            WordBreakToken::Word {
23040                token,
23041                grapheme_len,
23042            } => {
23043                in_whitespace = false;
23044                let current_prefix_len = if is_first_line {
23045                    first_line_prefix_len
23046                } else {
23047                    subsequent_lines_prefix_len
23048                };
23049                if current_line_len + grapheme_len > wrap_column
23050                    && current_line_len != current_prefix_len
23051                {
23052                    wrapped_text.push_str(current_line.trim_end());
23053                    wrapped_text.push('\n');
23054                    is_first_line = false;
23055                    current_line = subsequent_lines_prefix.clone();
23056                    current_line_len = subsequent_lines_prefix_len;
23057                }
23058                current_line.push_str(token);
23059                current_line_len += grapheme_len;
23060            }
23061            WordBreakToken::InlineWhitespace {
23062                mut token,
23063                mut grapheme_len,
23064            } => {
23065                in_whitespace = true;
23066                if have_preceding_whitespace && !preserve_existing_whitespace {
23067                    continue;
23068                }
23069                if !preserve_existing_whitespace {
23070                    // Keep a single whitespace grapheme as-is
23071                    if let Some(first) =
23072                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23073                    {
23074                        token = first;
23075                    } else {
23076                        token = " ";
23077                    }
23078                    grapheme_len = 1;
23079                }
23080                let current_prefix_len = if is_first_line {
23081                    first_line_prefix_len
23082                } else {
23083                    subsequent_lines_prefix_len
23084                };
23085                if current_line_len + grapheme_len > wrap_column {
23086                    wrapped_text.push_str(current_line.trim_end());
23087                    wrapped_text.push('\n');
23088                    is_first_line = false;
23089                    current_line = subsequent_lines_prefix.clone();
23090                    current_line_len = subsequent_lines_prefix_len;
23091                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23092                    current_line.push_str(token);
23093                    current_line_len += grapheme_len;
23094                }
23095            }
23096            WordBreakToken::Newline => {
23097                in_whitespace = true;
23098                let current_prefix_len = if is_first_line {
23099                    first_line_prefix_len
23100                } else {
23101                    subsequent_lines_prefix_len
23102                };
23103                if preserve_existing_whitespace {
23104                    wrapped_text.push_str(current_line.trim_end());
23105                    wrapped_text.push('\n');
23106                    is_first_line = false;
23107                    current_line = subsequent_lines_prefix.clone();
23108                    current_line_len = subsequent_lines_prefix_len;
23109                } else if have_preceding_whitespace {
23110                    continue;
23111                } else if current_line_len + 1 > wrap_column
23112                    && current_line_len != current_prefix_len
23113                {
23114                    wrapped_text.push_str(current_line.trim_end());
23115                    wrapped_text.push('\n');
23116                    is_first_line = false;
23117                    current_line = subsequent_lines_prefix.clone();
23118                    current_line_len = subsequent_lines_prefix_len;
23119                } else if current_line_len != current_prefix_len {
23120                    current_line.push(' ');
23121                    current_line_len += 1;
23122                }
23123            }
23124        }
23125    }
23126
23127    if !current_line.is_empty() {
23128        wrapped_text.push_str(&current_line);
23129    }
23130    wrapped_text
23131}
23132
23133#[test]
23134fn test_wrap_with_prefix() {
23135    assert_eq!(
23136        wrap_with_prefix(
23137            "# ".to_string(),
23138            "# ".to_string(),
23139            "abcdefg".to_string(),
23140            4,
23141            NonZeroU32::new(4).unwrap(),
23142            false,
23143        ),
23144        "# abcdefg"
23145    );
23146    assert_eq!(
23147        wrap_with_prefix(
23148            "".to_string(),
23149            "".to_string(),
23150            "\thello world".to_string(),
23151            8,
23152            NonZeroU32::new(4).unwrap(),
23153            false,
23154        ),
23155        "hello\nworld"
23156    );
23157    assert_eq!(
23158        wrap_with_prefix(
23159            "// ".to_string(),
23160            "// ".to_string(),
23161            "xx \nyy zz aa bb cc".to_string(),
23162            12,
23163            NonZeroU32::new(4).unwrap(),
23164            false,
23165        ),
23166        "// xx yy zz\n// aa bb cc"
23167    );
23168    assert_eq!(
23169        wrap_with_prefix(
23170            String::new(),
23171            String::new(),
23172            "这是什么 \n 钢笔".to_string(),
23173            3,
23174            NonZeroU32::new(4).unwrap(),
23175            false,
23176        ),
23177        "这是什\n么 钢\n"
23178    );
23179    assert_eq!(
23180        wrap_with_prefix(
23181            String::new(),
23182            String::new(),
23183            format!("foo{}bar", '\u{2009}'), // thin space
23184            80,
23185            NonZeroU32::new(4).unwrap(),
23186            false,
23187        ),
23188        format!("foo{}bar", '\u{2009}')
23189    );
23190}
23191
23192pub trait CollaborationHub {
23193    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23194    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23195    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23196}
23197
23198impl CollaborationHub for Entity<Project> {
23199    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23200        self.read(cx).collaborators()
23201    }
23202
23203    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23204        self.read(cx).user_store().read(cx).participant_indices()
23205    }
23206
23207    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23208        let this = self.read(cx);
23209        let user_ids = this.collaborators().values().map(|c| c.user_id);
23210        this.user_store().read(cx).participant_names(user_ids, cx)
23211    }
23212}
23213
23214pub trait SemanticsProvider {
23215    fn hover(
23216        &self,
23217        buffer: &Entity<Buffer>,
23218        position: text::Anchor,
23219        cx: &mut App,
23220    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23221
23222    fn inline_values(
23223        &self,
23224        buffer_handle: Entity<Buffer>,
23225        range: Range<text::Anchor>,
23226        cx: &mut App,
23227    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23228
23229    fn applicable_inlay_chunks(
23230        &self,
23231        buffer: &Entity<Buffer>,
23232        ranges: &[Range<text::Anchor>],
23233        cx: &mut App,
23234    ) -> Vec<Range<BufferRow>>;
23235
23236    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23237
23238    fn inlay_hints(
23239        &self,
23240        invalidate: InvalidationStrategy,
23241        buffer: Entity<Buffer>,
23242        ranges: Vec<Range<text::Anchor>>,
23243        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23244        cx: &mut App,
23245    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23246
23247    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23248
23249    fn document_highlights(
23250        &self,
23251        buffer: &Entity<Buffer>,
23252        position: text::Anchor,
23253        cx: &mut App,
23254    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23255
23256    fn definitions(
23257        &self,
23258        buffer: &Entity<Buffer>,
23259        position: text::Anchor,
23260        kind: GotoDefinitionKind,
23261        cx: &mut App,
23262    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23263
23264    fn range_for_rename(
23265        &self,
23266        buffer: &Entity<Buffer>,
23267        position: text::Anchor,
23268        cx: &mut App,
23269    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23270
23271    fn perform_rename(
23272        &self,
23273        buffer: &Entity<Buffer>,
23274        position: text::Anchor,
23275        new_name: String,
23276        cx: &mut App,
23277    ) -> Option<Task<Result<ProjectTransaction>>>;
23278}
23279
23280pub trait CompletionProvider {
23281    fn completions(
23282        &self,
23283        excerpt_id: ExcerptId,
23284        buffer: &Entity<Buffer>,
23285        buffer_position: text::Anchor,
23286        trigger: CompletionContext,
23287        window: &mut Window,
23288        cx: &mut Context<Editor>,
23289    ) -> Task<Result<Vec<CompletionResponse>>>;
23290
23291    fn resolve_completions(
23292        &self,
23293        _buffer: Entity<Buffer>,
23294        _completion_indices: Vec<usize>,
23295        _completions: Rc<RefCell<Box<[Completion]>>>,
23296        _cx: &mut Context<Editor>,
23297    ) -> Task<Result<bool>> {
23298        Task::ready(Ok(false))
23299    }
23300
23301    fn apply_additional_edits_for_completion(
23302        &self,
23303        _buffer: Entity<Buffer>,
23304        _completions: Rc<RefCell<Box<[Completion]>>>,
23305        _completion_index: usize,
23306        _push_to_history: bool,
23307        _cx: &mut Context<Editor>,
23308    ) -> Task<Result<Option<language::Transaction>>> {
23309        Task::ready(Ok(None))
23310    }
23311
23312    fn is_completion_trigger(
23313        &self,
23314        buffer: &Entity<Buffer>,
23315        position: language::Anchor,
23316        text: &str,
23317        trigger_in_words: bool,
23318        menu_is_open: bool,
23319        cx: &mut Context<Editor>,
23320    ) -> bool;
23321
23322    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23323
23324    fn sort_completions(&self) -> bool {
23325        true
23326    }
23327
23328    fn filter_completions(&self) -> bool {
23329        true
23330    }
23331
23332    fn show_snippets(&self) -> bool {
23333        false
23334    }
23335}
23336
23337pub trait CodeActionProvider {
23338    fn id(&self) -> Arc<str>;
23339
23340    fn code_actions(
23341        &self,
23342        buffer: &Entity<Buffer>,
23343        range: Range<text::Anchor>,
23344        window: &mut Window,
23345        cx: &mut App,
23346    ) -> Task<Result<Vec<CodeAction>>>;
23347
23348    fn apply_code_action(
23349        &self,
23350        buffer_handle: Entity<Buffer>,
23351        action: CodeAction,
23352        excerpt_id: ExcerptId,
23353        push_to_history: bool,
23354        window: &mut Window,
23355        cx: &mut App,
23356    ) -> Task<Result<ProjectTransaction>>;
23357}
23358
23359impl CodeActionProvider for Entity<Project> {
23360    fn id(&self) -> Arc<str> {
23361        "project".into()
23362    }
23363
23364    fn code_actions(
23365        &self,
23366        buffer: &Entity<Buffer>,
23367        range: Range<text::Anchor>,
23368        _window: &mut Window,
23369        cx: &mut App,
23370    ) -> Task<Result<Vec<CodeAction>>> {
23371        self.update(cx, |project, cx| {
23372            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23373            let code_actions = project.code_actions(buffer, range, None, cx);
23374            cx.background_spawn(async move {
23375                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23376                Ok(code_lens_actions
23377                    .context("code lens fetch")?
23378                    .into_iter()
23379                    .flatten()
23380                    .chain(
23381                        code_actions
23382                            .context("code action fetch")?
23383                            .into_iter()
23384                            .flatten(),
23385                    )
23386                    .collect())
23387            })
23388        })
23389    }
23390
23391    fn apply_code_action(
23392        &self,
23393        buffer_handle: Entity<Buffer>,
23394        action: CodeAction,
23395        _excerpt_id: ExcerptId,
23396        push_to_history: bool,
23397        _window: &mut Window,
23398        cx: &mut App,
23399    ) -> Task<Result<ProjectTransaction>> {
23400        self.update(cx, |project, cx| {
23401            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23402        })
23403    }
23404}
23405
23406fn snippet_completions(
23407    project: &Project,
23408    buffer: &Entity<Buffer>,
23409    buffer_anchor: text::Anchor,
23410    classifier: CharClassifier,
23411    cx: &mut App,
23412) -> Task<Result<CompletionResponse>> {
23413    let languages = buffer.read(cx).languages_at(buffer_anchor);
23414    let snippet_store = project.snippets().read(cx);
23415
23416    let scopes: Vec<_> = languages
23417        .iter()
23418        .filter_map(|language| {
23419            let language_name = language.lsp_id();
23420            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23421
23422            if snippets.is_empty() {
23423                None
23424            } else {
23425                Some((language.default_scope(), snippets))
23426            }
23427        })
23428        .collect();
23429
23430    if scopes.is_empty() {
23431        return Task::ready(Ok(CompletionResponse {
23432            completions: vec![],
23433            display_options: CompletionDisplayOptions::default(),
23434            is_incomplete: false,
23435        }));
23436    }
23437
23438    let snapshot = buffer.read(cx).text_snapshot();
23439    let executor = cx.background_executor().clone();
23440
23441    cx.background_spawn(async move {
23442        let is_word_char = |c| classifier.is_word(c);
23443
23444        let mut is_incomplete = false;
23445        let mut completions: Vec<Completion> = Vec::new();
23446
23447        const MAX_PREFIX_LEN: usize = 128;
23448        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
23449        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
23450        let window_start = snapshot.clip_offset(window_start, Bias::Left);
23451
23452        let max_buffer_window: String = snapshot
23453            .text_for_range(window_start..buffer_offset)
23454            .collect();
23455
23456        if max_buffer_window.is_empty() {
23457            return Ok(CompletionResponse {
23458                completions: vec![],
23459                display_options: CompletionDisplayOptions::default(),
23460                is_incomplete: true,
23461            });
23462        }
23463
23464        for (_scope, snippets) in scopes.into_iter() {
23465            // Sort snippets by word count to match longer snippet prefixes first.
23466            let mut sorted_snippet_candidates = snippets
23467                .iter()
23468                .enumerate()
23469                .flat_map(|(snippet_ix, snippet)| {
23470                    snippet
23471                        .prefix
23472                        .iter()
23473                        .enumerate()
23474                        .map(move |(prefix_ix, prefix)| {
23475                            let word_count =
23476                                snippet_candidate_suffixes(prefix, is_word_char).count();
23477                            ((snippet_ix, prefix_ix), prefix, word_count)
23478                        })
23479                })
23480                .collect_vec();
23481            sorted_snippet_candidates
23482                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
23483
23484            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
23485
23486            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
23487                .take(
23488                    sorted_snippet_candidates
23489                        .first()
23490                        .map(|(_, _, word_count)| *word_count)
23491                        .unwrap_or_default(),
23492                )
23493                .collect_vec();
23494
23495            const MAX_RESULTS: usize = 100;
23496            // Each match also remembers how many characters from the buffer it consumed
23497            let mut matches: Vec<(StringMatch, usize)> = vec![];
23498
23499            let mut snippet_list_cutoff_index = 0;
23500            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
23501                let word_count = buffer_index + 1;
23502                // Increase `snippet_list_cutoff_index` until we have all of the
23503                // snippets with sufficiently many words.
23504                while sorted_snippet_candidates
23505                    .get(snippet_list_cutoff_index)
23506                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
23507                        *snippet_word_count >= word_count
23508                    })
23509                {
23510                    snippet_list_cutoff_index += 1;
23511                }
23512
23513                // Take only the candidates with at least `word_count` many words
23514                let snippet_candidates_at_word_len =
23515                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
23516
23517                let candidates = snippet_candidates_at_word_len
23518                    .iter()
23519                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
23520                    .enumerate() // index in `sorted_snippet_candidates`
23521                    // First char must match
23522                    .filter(|(_ix, prefix)| {
23523                        itertools::equal(
23524                            prefix
23525                                .chars()
23526                                .next()
23527                                .into_iter()
23528                                .flat_map(|c| c.to_lowercase()),
23529                            buffer_window
23530                                .chars()
23531                                .next()
23532                                .into_iter()
23533                                .flat_map(|c| c.to_lowercase()),
23534                        )
23535                    })
23536                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
23537                    .collect::<Vec<StringMatchCandidate>>();
23538
23539                matches.extend(
23540                    fuzzy::match_strings(
23541                        &candidates,
23542                        &buffer_window,
23543                        buffer_window.chars().any(|c| c.is_uppercase()),
23544                        true,
23545                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
23546                        &Default::default(),
23547                        executor.clone(),
23548                    )
23549                    .await
23550                    .into_iter()
23551                    .map(|string_match| (string_match, buffer_window.len())),
23552                );
23553
23554                if matches.len() >= MAX_RESULTS {
23555                    break;
23556                }
23557            }
23558
23559            let to_lsp = |point: &text::Anchor| {
23560                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23561                point_to_lsp(end)
23562            };
23563            let lsp_end = to_lsp(&buffer_anchor);
23564
23565            if matches.len() >= MAX_RESULTS {
23566                is_incomplete = true;
23567            }
23568
23569            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
23570                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
23571                    sorted_snippet_candidates[string_match.candidate_id];
23572                let snippet = &snippets[snippet_index];
23573                let start = buffer_offset - buffer_window_len;
23574                let start = snapshot.anchor_before(start);
23575                let range = start..buffer_anchor;
23576                let lsp_start = to_lsp(&start);
23577                let lsp_range = lsp::Range {
23578                    start: lsp_start,
23579                    end: lsp_end,
23580                };
23581                Completion {
23582                    replace_range: range,
23583                    new_text: snippet.body.clone(),
23584                    source: CompletionSource::Lsp {
23585                        insert_range: None,
23586                        server_id: LanguageServerId(usize::MAX),
23587                        resolved: true,
23588                        lsp_completion: Box::new(lsp::CompletionItem {
23589                            label: snippet.prefix.first().unwrap().clone(),
23590                            kind: Some(CompletionItemKind::SNIPPET),
23591                            label_details: snippet.description.as_ref().map(|description| {
23592                                lsp::CompletionItemLabelDetails {
23593                                    detail: Some(description.clone()),
23594                                    description: None,
23595                                }
23596                            }),
23597                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23598                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23599                                lsp::InsertReplaceEdit {
23600                                    new_text: snippet.body.clone(),
23601                                    insert: lsp_range,
23602                                    replace: lsp_range,
23603                                },
23604                            )),
23605                            filter_text: Some(snippet.body.clone()),
23606                            sort_text: Some(char::MAX.to_string()),
23607                            ..lsp::CompletionItem::default()
23608                        }),
23609                        lsp_defaults: None,
23610                    },
23611                    label: CodeLabel {
23612                        text: matching_prefix.clone(),
23613                        runs: Vec::new(),
23614                        filter_range: 0..matching_prefix.len(),
23615                    },
23616                    icon_path: None,
23617                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23618                        single_line: snippet.name.clone().into(),
23619                        plain_text: snippet
23620                            .description
23621                            .clone()
23622                            .map(|description| description.into()),
23623                    }),
23624                    insert_text_mode: None,
23625                    confirm: None,
23626                    match_start: Some(start),
23627                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
23628                }
23629            }));
23630        }
23631
23632        Ok(CompletionResponse {
23633            completions,
23634            display_options: CompletionDisplayOptions::default(),
23635            is_incomplete,
23636        })
23637    })
23638}
23639
23640impl CompletionProvider for Entity<Project> {
23641    fn completions(
23642        &self,
23643        _excerpt_id: ExcerptId,
23644        buffer: &Entity<Buffer>,
23645        buffer_position: text::Anchor,
23646        options: CompletionContext,
23647        _window: &mut Window,
23648        cx: &mut Context<Editor>,
23649    ) -> Task<Result<Vec<CompletionResponse>>> {
23650        self.update(cx, |project, cx| {
23651            let task = project.completions(buffer, buffer_position, options, cx);
23652            cx.background_spawn(task)
23653        })
23654    }
23655
23656    fn resolve_completions(
23657        &self,
23658        buffer: Entity<Buffer>,
23659        completion_indices: Vec<usize>,
23660        completions: Rc<RefCell<Box<[Completion]>>>,
23661        cx: &mut Context<Editor>,
23662    ) -> Task<Result<bool>> {
23663        self.update(cx, |project, cx| {
23664            project.lsp_store().update(cx, |lsp_store, cx| {
23665                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23666            })
23667        })
23668    }
23669
23670    fn apply_additional_edits_for_completion(
23671        &self,
23672        buffer: Entity<Buffer>,
23673        completions: Rc<RefCell<Box<[Completion]>>>,
23674        completion_index: usize,
23675        push_to_history: bool,
23676        cx: &mut Context<Editor>,
23677    ) -> Task<Result<Option<language::Transaction>>> {
23678        self.update(cx, |project, cx| {
23679            project.lsp_store().update(cx, |lsp_store, cx| {
23680                lsp_store.apply_additional_edits_for_completion(
23681                    buffer,
23682                    completions,
23683                    completion_index,
23684                    push_to_history,
23685                    cx,
23686                )
23687            })
23688        })
23689    }
23690
23691    fn is_completion_trigger(
23692        &self,
23693        buffer: &Entity<Buffer>,
23694        position: language::Anchor,
23695        text: &str,
23696        trigger_in_words: bool,
23697        menu_is_open: bool,
23698        cx: &mut Context<Editor>,
23699    ) -> bool {
23700        let mut chars = text.chars();
23701        let char = if let Some(char) = chars.next() {
23702            char
23703        } else {
23704            return false;
23705        };
23706        if chars.next().is_some() {
23707            return false;
23708        }
23709
23710        let buffer = buffer.read(cx);
23711        let snapshot = buffer.snapshot();
23712        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23713            return false;
23714        }
23715        let classifier = snapshot
23716            .char_classifier_at(position)
23717            .scope_context(Some(CharScopeContext::Completion));
23718        if trigger_in_words && classifier.is_word(char) {
23719            return true;
23720        }
23721
23722        buffer.completion_triggers().contains(text)
23723    }
23724
23725    fn show_snippets(&self) -> bool {
23726        true
23727    }
23728}
23729
23730impl SemanticsProvider for Entity<Project> {
23731    fn hover(
23732        &self,
23733        buffer: &Entity<Buffer>,
23734        position: text::Anchor,
23735        cx: &mut App,
23736    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23737        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23738    }
23739
23740    fn document_highlights(
23741        &self,
23742        buffer: &Entity<Buffer>,
23743        position: text::Anchor,
23744        cx: &mut App,
23745    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23746        Some(self.update(cx, |project, cx| {
23747            project.document_highlights(buffer, position, cx)
23748        }))
23749    }
23750
23751    fn definitions(
23752        &self,
23753        buffer: &Entity<Buffer>,
23754        position: text::Anchor,
23755        kind: GotoDefinitionKind,
23756        cx: &mut App,
23757    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23758        Some(self.update(cx, |project, cx| match kind {
23759            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23760            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23761            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23762            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23763        }))
23764    }
23765
23766    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23767        self.update(cx, |project, cx| {
23768            if project
23769                .active_debug_session(cx)
23770                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23771            {
23772                return true;
23773            }
23774
23775            buffer.update(cx, |buffer, cx| {
23776                project.any_language_server_supports_inlay_hints(buffer, cx)
23777            })
23778        })
23779    }
23780
23781    fn inline_values(
23782        &self,
23783        buffer_handle: Entity<Buffer>,
23784        range: Range<text::Anchor>,
23785        cx: &mut App,
23786    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23787        self.update(cx, |project, cx| {
23788            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23789
23790            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23791        })
23792    }
23793
23794    fn applicable_inlay_chunks(
23795        &self,
23796        buffer: &Entity<Buffer>,
23797        ranges: &[Range<text::Anchor>],
23798        cx: &mut App,
23799    ) -> Vec<Range<BufferRow>> {
23800        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23801            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23802        })
23803    }
23804
23805    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23806        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23807            lsp_store.invalidate_inlay_hints(for_buffers)
23808        });
23809    }
23810
23811    fn inlay_hints(
23812        &self,
23813        invalidate: InvalidationStrategy,
23814        buffer: Entity<Buffer>,
23815        ranges: Vec<Range<text::Anchor>>,
23816        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23817        cx: &mut App,
23818    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23819        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23820            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23821        }))
23822    }
23823
23824    fn range_for_rename(
23825        &self,
23826        buffer: &Entity<Buffer>,
23827        position: text::Anchor,
23828        cx: &mut App,
23829    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23830        Some(self.update(cx, |project, cx| {
23831            let buffer = buffer.clone();
23832            let task = project.prepare_rename(buffer.clone(), position, cx);
23833            cx.spawn(async move |_, cx| {
23834                Ok(match task.await? {
23835                    PrepareRenameResponse::Success(range) => Some(range),
23836                    PrepareRenameResponse::InvalidPosition => None,
23837                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23838                        // Fallback on using TreeSitter info to determine identifier range
23839                        buffer.read_with(cx, |buffer, _| {
23840                            let snapshot = buffer.snapshot();
23841                            let (range, kind) = snapshot.surrounding_word(position, None);
23842                            if kind != Some(CharKind::Word) {
23843                                return None;
23844                            }
23845                            Some(
23846                                snapshot.anchor_before(range.start)
23847                                    ..snapshot.anchor_after(range.end),
23848                            )
23849                        })?
23850                    }
23851                })
23852            })
23853        }))
23854    }
23855
23856    fn perform_rename(
23857        &self,
23858        buffer: &Entity<Buffer>,
23859        position: text::Anchor,
23860        new_name: String,
23861        cx: &mut App,
23862    ) -> Option<Task<Result<ProjectTransaction>>> {
23863        Some(self.update(cx, |project, cx| {
23864            project.perform_rename(buffer.clone(), position, new_name, cx)
23865        }))
23866    }
23867}
23868
23869fn consume_contiguous_rows(
23870    contiguous_row_selections: &mut Vec<Selection<Point>>,
23871    selection: &Selection<Point>,
23872    display_map: &DisplaySnapshot,
23873    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23874) -> (MultiBufferRow, MultiBufferRow) {
23875    contiguous_row_selections.push(selection.clone());
23876    let start_row = starting_row(selection, display_map);
23877    let mut end_row = ending_row(selection, display_map);
23878
23879    while let Some(next_selection) = selections.peek() {
23880        if next_selection.start.row <= end_row.0 {
23881            end_row = ending_row(next_selection, display_map);
23882            contiguous_row_selections.push(selections.next().unwrap().clone());
23883        } else {
23884            break;
23885        }
23886    }
23887    (start_row, end_row)
23888}
23889
23890fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23891    if selection.start.column > 0 {
23892        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23893    } else {
23894        MultiBufferRow(selection.start.row)
23895    }
23896}
23897
23898fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23899    if next_selection.end.column > 0 || next_selection.is_empty() {
23900        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23901    } else {
23902        MultiBufferRow(next_selection.end.row)
23903    }
23904}
23905
23906impl EditorSnapshot {
23907    pub fn remote_selections_in_range<'a>(
23908        &'a self,
23909        range: &'a Range<Anchor>,
23910        collaboration_hub: &dyn CollaborationHub,
23911        cx: &'a App,
23912    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23913        let participant_names = collaboration_hub.user_names(cx);
23914        let participant_indices = collaboration_hub.user_participant_indices(cx);
23915        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23916        let collaborators_by_replica_id = collaborators_by_peer_id
23917            .values()
23918            .map(|collaborator| (collaborator.replica_id, collaborator))
23919            .collect::<HashMap<_, _>>();
23920        self.buffer_snapshot()
23921            .selections_in_range(range, false)
23922            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23923                if replica_id == ReplicaId::AGENT {
23924                    Some(RemoteSelection {
23925                        replica_id,
23926                        selection,
23927                        cursor_shape,
23928                        line_mode,
23929                        collaborator_id: CollaboratorId::Agent,
23930                        user_name: Some("Agent".into()),
23931                        color: cx.theme().players().agent(),
23932                    })
23933                } else {
23934                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23935                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23936                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23937                    Some(RemoteSelection {
23938                        replica_id,
23939                        selection,
23940                        cursor_shape,
23941                        line_mode,
23942                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23943                        user_name,
23944                        color: if let Some(index) = participant_index {
23945                            cx.theme().players().color_for_participant(index.0)
23946                        } else {
23947                            cx.theme().players().absent()
23948                        },
23949                    })
23950                }
23951            })
23952    }
23953
23954    pub fn hunks_for_ranges(
23955        &self,
23956        ranges: impl IntoIterator<Item = Range<Point>>,
23957    ) -> Vec<MultiBufferDiffHunk> {
23958        let mut hunks = Vec::new();
23959        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23960            HashMap::default();
23961        for query_range in ranges {
23962            let query_rows =
23963                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23964            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23965                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23966            ) {
23967                // Include deleted hunks that are adjacent to the query range, because
23968                // otherwise they would be missed.
23969                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23970                if hunk.status().is_deleted() {
23971                    intersects_range |= hunk.row_range.start == query_rows.end;
23972                    intersects_range |= hunk.row_range.end == query_rows.start;
23973                }
23974                if intersects_range {
23975                    if !processed_buffer_rows
23976                        .entry(hunk.buffer_id)
23977                        .or_default()
23978                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23979                    {
23980                        continue;
23981                    }
23982                    hunks.push(hunk);
23983                }
23984            }
23985        }
23986
23987        hunks
23988    }
23989
23990    fn display_diff_hunks_for_rows<'a>(
23991        &'a self,
23992        display_rows: Range<DisplayRow>,
23993        folded_buffers: &'a HashSet<BufferId>,
23994    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23995        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23996        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23997
23998        self.buffer_snapshot()
23999            .diff_hunks_in_range(buffer_start..buffer_end)
24000            .filter_map(|hunk| {
24001                if folded_buffers.contains(&hunk.buffer_id) {
24002                    return None;
24003                }
24004
24005                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24006                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24007
24008                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24009                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24010
24011                let display_hunk = if hunk_display_start.column() != 0 {
24012                    DisplayDiffHunk::Folded {
24013                        display_row: hunk_display_start.row(),
24014                    }
24015                } else {
24016                    let mut end_row = hunk_display_end.row();
24017                    if hunk_display_end.column() > 0 {
24018                        end_row.0 += 1;
24019                    }
24020                    let is_created_file = hunk.is_created_file();
24021                    DisplayDiffHunk::Unfolded {
24022                        status: hunk.status(),
24023                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24024                            ..hunk.diff_base_byte_range.end.0,
24025                        display_row_range: hunk_display_start.row()..end_row,
24026                        multi_buffer_range: Anchor::range_in_buffer(
24027                            hunk.excerpt_id,
24028                            hunk.buffer_id,
24029                            hunk.buffer_range,
24030                        ),
24031                        is_created_file,
24032                    }
24033                };
24034
24035                Some(display_hunk)
24036            })
24037    }
24038
24039    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24040        self.display_snapshot
24041            .buffer_snapshot()
24042            .language_at(position)
24043    }
24044
24045    pub fn is_focused(&self) -> bool {
24046        self.is_focused
24047    }
24048
24049    pub fn placeholder_text(&self) -> Option<String> {
24050        self.placeholder_display_snapshot
24051            .as_ref()
24052            .map(|display_map| display_map.text())
24053    }
24054
24055    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24056        self.scroll_anchor.scroll_position(&self.display_snapshot)
24057    }
24058
24059    fn gutter_dimensions(
24060        &self,
24061        font_id: FontId,
24062        font_size: Pixels,
24063        max_line_number_width: Pixels,
24064        cx: &App,
24065    ) -> Option<GutterDimensions> {
24066        if !self.show_gutter {
24067            return None;
24068        }
24069
24070        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
24071        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
24072
24073        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24074            matches!(
24075                ProjectSettings::get_global(cx).git.git_gutter,
24076                GitGutterSetting::TrackedFiles
24077            )
24078        });
24079        let gutter_settings = EditorSettings::get_global(cx).gutter;
24080        let show_line_numbers = self
24081            .show_line_numbers
24082            .unwrap_or(gutter_settings.line_numbers);
24083        let line_gutter_width = if show_line_numbers {
24084            // Avoid flicker-like gutter resizes when the line number gains another digit by
24085            // only resizing the gutter on files with > 10**min_line_number_digits lines.
24086            let min_width_for_number_on_gutter =
24087                ch_advance * gutter_settings.min_line_number_digits as f32;
24088            max_line_number_width.max(min_width_for_number_on_gutter)
24089        } else {
24090            0.0.into()
24091        };
24092
24093        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24094        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24095
24096        let git_blame_entries_width =
24097            self.git_blame_gutter_max_author_length
24098                .map(|max_author_length| {
24099                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24100                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24101
24102                    /// The number of characters to dedicate to gaps and margins.
24103                    const SPACING_WIDTH: usize = 4;
24104
24105                    let max_char_count = max_author_length.min(renderer.max_author_length())
24106                        + ::git::SHORT_SHA_LENGTH
24107                        + MAX_RELATIVE_TIMESTAMP.len()
24108                        + SPACING_WIDTH;
24109
24110                    ch_advance * max_char_count
24111                });
24112
24113        let is_singleton = self.buffer_snapshot().is_singleton();
24114
24115        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24116        left_padding += if !is_singleton {
24117            ch_width * 4.0
24118        } else if show_runnables || show_breakpoints {
24119            ch_width * 3.0
24120        } else if show_git_gutter && show_line_numbers {
24121            ch_width * 2.0
24122        } else if show_git_gutter || show_line_numbers {
24123            ch_width
24124        } else {
24125            px(0.)
24126        };
24127
24128        let shows_folds = is_singleton && gutter_settings.folds;
24129
24130        let right_padding = if shows_folds && show_line_numbers {
24131            ch_width * 4.0
24132        } else if shows_folds || (!is_singleton && show_line_numbers) {
24133            ch_width * 3.0
24134        } else if show_line_numbers {
24135            ch_width
24136        } else {
24137            px(0.)
24138        };
24139
24140        Some(GutterDimensions {
24141            left_padding,
24142            right_padding,
24143            width: line_gutter_width + left_padding + right_padding,
24144            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24145            git_blame_entries_width,
24146        })
24147    }
24148
24149    pub fn render_crease_toggle(
24150        &self,
24151        buffer_row: MultiBufferRow,
24152        row_contains_cursor: bool,
24153        editor: Entity<Editor>,
24154        window: &mut Window,
24155        cx: &mut App,
24156    ) -> Option<AnyElement> {
24157        let folded = self.is_line_folded(buffer_row);
24158        let mut is_foldable = false;
24159
24160        if let Some(crease) = self
24161            .crease_snapshot
24162            .query_row(buffer_row, self.buffer_snapshot())
24163        {
24164            is_foldable = true;
24165            match crease {
24166                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24167                    if let Some(render_toggle) = render_toggle {
24168                        let toggle_callback =
24169                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24170                                if folded {
24171                                    editor.update(cx, |editor, cx| {
24172                                        editor.fold_at(buffer_row, window, cx)
24173                                    });
24174                                } else {
24175                                    editor.update(cx, |editor, cx| {
24176                                        editor.unfold_at(buffer_row, window, cx)
24177                                    });
24178                                }
24179                            });
24180                        return Some((render_toggle)(
24181                            buffer_row,
24182                            folded,
24183                            toggle_callback,
24184                            window,
24185                            cx,
24186                        ));
24187                    }
24188                }
24189            }
24190        }
24191
24192        is_foldable |= self.starts_indent(buffer_row);
24193
24194        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24195            Some(
24196                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24197                    .toggle_state(folded)
24198                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24199                        if folded {
24200                            this.unfold_at(buffer_row, window, cx);
24201                        } else {
24202                            this.fold_at(buffer_row, window, cx);
24203                        }
24204                    }))
24205                    .into_any_element(),
24206            )
24207        } else {
24208            None
24209        }
24210    }
24211
24212    pub fn render_crease_trailer(
24213        &self,
24214        buffer_row: MultiBufferRow,
24215        window: &mut Window,
24216        cx: &mut App,
24217    ) -> Option<AnyElement> {
24218        let folded = self.is_line_folded(buffer_row);
24219        if let Crease::Inline { render_trailer, .. } = self
24220            .crease_snapshot
24221            .query_row(buffer_row, self.buffer_snapshot())?
24222        {
24223            let render_trailer = render_trailer.as_ref()?;
24224            Some(render_trailer(buffer_row, folded, window, cx))
24225        } else {
24226            None
24227        }
24228    }
24229}
24230
24231impl Deref for EditorSnapshot {
24232    type Target = DisplaySnapshot;
24233
24234    fn deref(&self) -> &Self::Target {
24235        &self.display_snapshot
24236    }
24237}
24238
24239#[derive(Clone, Debug, PartialEq, Eq)]
24240pub enum EditorEvent {
24241    InputIgnored {
24242        text: Arc<str>,
24243    },
24244    InputHandled {
24245        utf16_range_to_replace: Option<Range<isize>>,
24246        text: Arc<str>,
24247    },
24248    ExcerptsAdded {
24249        buffer: Entity<Buffer>,
24250        predecessor: ExcerptId,
24251        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24252    },
24253    ExcerptsRemoved {
24254        ids: Vec<ExcerptId>,
24255        removed_buffer_ids: Vec<BufferId>,
24256    },
24257    BufferFoldToggled {
24258        ids: Vec<ExcerptId>,
24259        folded: bool,
24260    },
24261    ExcerptsEdited {
24262        ids: Vec<ExcerptId>,
24263    },
24264    ExcerptsExpanded {
24265        ids: Vec<ExcerptId>,
24266    },
24267    BufferEdited,
24268    Edited {
24269        transaction_id: clock::Lamport,
24270    },
24271    Reparsed(BufferId),
24272    Focused,
24273    FocusedIn,
24274    Blurred,
24275    DirtyChanged,
24276    Saved,
24277    TitleChanged,
24278    SelectionsChanged {
24279        local: bool,
24280    },
24281    ScrollPositionChanged {
24282        local: bool,
24283        autoscroll: bool,
24284    },
24285    TransactionUndone {
24286        transaction_id: clock::Lamport,
24287    },
24288    TransactionBegun {
24289        transaction_id: clock::Lamport,
24290    },
24291    CursorShapeChanged,
24292    BreadcrumbsChanged,
24293    PushedToNavHistory {
24294        anchor: Anchor,
24295        is_deactivate: bool,
24296    },
24297}
24298
24299impl EventEmitter<EditorEvent> for Editor {}
24300
24301impl Focusable for Editor {
24302    fn focus_handle(&self, _cx: &App) -> FocusHandle {
24303        self.focus_handle.clone()
24304    }
24305}
24306
24307impl Render for Editor {
24308    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24309        let settings = ThemeSettings::get_global(cx);
24310
24311        let mut text_style = match self.mode {
24312            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24313                color: cx.theme().colors().editor_foreground,
24314                font_family: settings.ui_font.family.clone(),
24315                font_features: settings.ui_font.features.clone(),
24316                font_fallbacks: settings.ui_font.fallbacks.clone(),
24317                font_size: rems(0.875).into(),
24318                font_weight: settings.ui_font.weight,
24319                line_height: relative(settings.buffer_line_height.value()),
24320                ..Default::default()
24321            },
24322            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24323                color: cx.theme().colors().editor_foreground,
24324                font_family: settings.buffer_font.family.clone(),
24325                font_features: settings.buffer_font.features.clone(),
24326                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24327                font_size: settings.buffer_font_size(cx).into(),
24328                font_weight: settings.buffer_font.weight,
24329                line_height: relative(settings.buffer_line_height.value()),
24330                ..Default::default()
24331            },
24332        };
24333        if let Some(text_style_refinement) = &self.text_style_refinement {
24334            text_style.refine(text_style_refinement)
24335        }
24336
24337        let background = match self.mode {
24338            EditorMode::SingleLine => cx.theme().system().transparent,
24339            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24340            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24341            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24342        };
24343
24344        EditorElement::new(
24345            &cx.entity(),
24346            EditorStyle {
24347                background,
24348                border: cx.theme().colors().border,
24349                local_player: cx.theme().players().local(),
24350                text: text_style,
24351                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24352                syntax: cx.theme().syntax().clone(),
24353                status: cx.theme().status().clone(),
24354                inlay_hints_style: make_inlay_hints_style(cx),
24355                edit_prediction_styles: make_suggestion_styles(cx),
24356                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24357                show_underlines: self.diagnostics_enabled(),
24358            },
24359        )
24360    }
24361}
24362
24363impl EntityInputHandler for Editor {
24364    fn text_for_range(
24365        &mut self,
24366        range_utf16: Range<usize>,
24367        adjusted_range: &mut Option<Range<usize>>,
24368        _: &mut Window,
24369        cx: &mut Context<Self>,
24370    ) -> Option<String> {
24371        let snapshot = self.buffer.read(cx).read(cx);
24372        let start = snapshot.clip_offset_utf16(
24373            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
24374            Bias::Left,
24375        );
24376        let end = snapshot.clip_offset_utf16(
24377            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
24378            Bias::Right,
24379        );
24380        if (start.0.0..end.0.0) != range_utf16 {
24381            adjusted_range.replace(start.0.0..end.0.0);
24382        }
24383        Some(snapshot.text_for_range(start..end).collect())
24384    }
24385
24386    fn selected_text_range(
24387        &mut self,
24388        ignore_disabled_input: bool,
24389        _: &mut Window,
24390        cx: &mut Context<Self>,
24391    ) -> Option<UTF16Selection> {
24392        // Prevent the IME menu from appearing when holding down an alphabetic key
24393        // while input is disabled.
24394        if !ignore_disabled_input && !self.input_enabled {
24395            return None;
24396        }
24397
24398        let selection = self
24399            .selections
24400            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24401        let range = selection.range();
24402
24403        Some(UTF16Selection {
24404            range: range.start.0.0..range.end.0.0,
24405            reversed: selection.reversed,
24406        })
24407    }
24408
24409    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24410        let snapshot = self.buffer.read(cx).read(cx);
24411        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24412        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
24413    }
24414
24415    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24416        self.clear_highlights::<InputComposition>(cx);
24417        self.ime_transaction.take();
24418    }
24419
24420    fn replace_text_in_range(
24421        &mut self,
24422        range_utf16: Option<Range<usize>>,
24423        text: &str,
24424        window: &mut Window,
24425        cx: &mut Context<Self>,
24426    ) {
24427        if !self.input_enabled {
24428            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24429            return;
24430        }
24431
24432        self.transact(window, cx, |this, window, cx| {
24433            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24434                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24435                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24436                Some(this.selection_replacement_ranges(range_utf16, cx))
24437            } else {
24438                this.marked_text_ranges(cx)
24439            };
24440
24441            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24442                let newest_selection_id = this.selections.newest_anchor().id;
24443                this.selections
24444                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24445                    .iter()
24446                    .zip(ranges_to_replace.iter())
24447                    .find_map(|(selection, range)| {
24448                        if selection.id == newest_selection_id {
24449                            Some(
24450                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24451                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24452                            )
24453                        } else {
24454                            None
24455                        }
24456                    })
24457            });
24458
24459            cx.emit(EditorEvent::InputHandled {
24460                utf16_range_to_replace: range_to_replace,
24461                text: text.into(),
24462            });
24463
24464            if let Some(new_selected_ranges) = new_selected_ranges {
24465                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24466                    selections.select_ranges(new_selected_ranges)
24467                });
24468                this.backspace(&Default::default(), window, cx);
24469            }
24470
24471            this.handle_input(text, window, cx);
24472        });
24473
24474        if let Some(transaction) = self.ime_transaction {
24475            self.buffer.update(cx, |buffer, cx| {
24476                buffer.group_until_transaction(transaction, cx);
24477            });
24478        }
24479
24480        self.unmark_text(window, cx);
24481    }
24482
24483    fn replace_and_mark_text_in_range(
24484        &mut self,
24485        range_utf16: Option<Range<usize>>,
24486        text: &str,
24487        new_selected_range_utf16: Option<Range<usize>>,
24488        window: &mut Window,
24489        cx: &mut Context<Self>,
24490    ) {
24491        if !self.input_enabled {
24492            return;
24493        }
24494
24495        let transaction = self.transact(window, cx, |this, window, cx| {
24496            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24497                let snapshot = this.buffer.read(cx).read(cx);
24498                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24499                    for marked_range in &mut marked_ranges {
24500                        marked_range.end = marked_range.start + relative_range_utf16.end;
24501                        marked_range.start += relative_range_utf16.start;
24502                        marked_range.start =
24503                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24504                        marked_range.end =
24505                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24506                    }
24507                }
24508                Some(marked_ranges)
24509            } else if let Some(range_utf16) = range_utf16 {
24510                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24511                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24512                Some(this.selection_replacement_ranges(range_utf16, cx))
24513            } else {
24514                None
24515            };
24516
24517            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24518                let newest_selection_id = this.selections.newest_anchor().id;
24519                this.selections
24520                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24521                    .iter()
24522                    .zip(ranges_to_replace.iter())
24523                    .find_map(|(selection, range)| {
24524                        if selection.id == newest_selection_id {
24525                            Some(
24526                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24527                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24528                            )
24529                        } else {
24530                            None
24531                        }
24532                    })
24533            });
24534
24535            cx.emit(EditorEvent::InputHandled {
24536                utf16_range_to_replace: range_to_replace,
24537                text: text.into(),
24538            });
24539
24540            if let Some(ranges) = ranges_to_replace {
24541                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24542                    s.select_ranges(ranges)
24543                });
24544            }
24545
24546            let marked_ranges = {
24547                let snapshot = this.buffer.read(cx).read(cx);
24548                this.selections
24549                    .disjoint_anchors_arc()
24550                    .iter()
24551                    .map(|selection| {
24552                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24553                    })
24554                    .collect::<Vec<_>>()
24555            };
24556
24557            if text.is_empty() {
24558                this.unmark_text(window, cx);
24559            } else {
24560                this.highlight_text::<InputComposition>(
24561                    marked_ranges.clone(),
24562                    HighlightStyle {
24563                        underline: Some(UnderlineStyle {
24564                            thickness: px(1.),
24565                            color: None,
24566                            wavy: false,
24567                        }),
24568                        ..Default::default()
24569                    },
24570                    cx,
24571                );
24572            }
24573
24574            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24575            let use_autoclose = this.use_autoclose;
24576            let use_auto_surround = this.use_auto_surround;
24577            this.set_use_autoclose(false);
24578            this.set_use_auto_surround(false);
24579            this.handle_input(text, window, cx);
24580            this.set_use_autoclose(use_autoclose);
24581            this.set_use_auto_surround(use_auto_surround);
24582
24583            if let Some(new_selected_range) = new_selected_range_utf16 {
24584                let snapshot = this.buffer.read(cx).read(cx);
24585                let new_selected_ranges = marked_ranges
24586                    .into_iter()
24587                    .map(|marked_range| {
24588                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24589                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
24590                            insertion_start.0 + new_selected_range.start,
24591                        ));
24592                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
24593                            insertion_start.0 + new_selected_range.end,
24594                        ));
24595                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24596                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24597                    })
24598                    .collect::<Vec<_>>();
24599
24600                drop(snapshot);
24601                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24602                    selections.select_ranges(new_selected_ranges)
24603                });
24604            }
24605        });
24606
24607        self.ime_transaction = self.ime_transaction.or(transaction);
24608        if let Some(transaction) = self.ime_transaction {
24609            self.buffer.update(cx, |buffer, cx| {
24610                buffer.group_until_transaction(transaction, cx);
24611            });
24612        }
24613
24614        if self.text_highlights::<InputComposition>(cx).is_none() {
24615            self.ime_transaction.take();
24616        }
24617    }
24618
24619    fn bounds_for_range(
24620        &mut self,
24621        range_utf16: Range<usize>,
24622        element_bounds: gpui::Bounds<Pixels>,
24623        window: &mut Window,
24624        cx: &mut Context<Self>,
24625    ) -> Option<gpui::Bounds<Pixels>> {
24626        let text_layout_details = self.text_layout_details(window);
24627        let CharacterDimensions {
24628            em_width,
24629            em_advance,
24630            line_height,
24631        } = self.character_dimensions(window);
24632
24633        let snapshot = self.snapshot(window, cx);
24634        let scroll_position = snapshot.scroll_position();
24635        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24636
24637        let start =
24638            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
24639        let x = Pixels::from(
24640            ScrollOffset::from(
24641                snapshot.x_for_display_point(start, &text_layout_details)
24642                    + self.gutter_dimensions.full_width(),
24643            ) - scroll_left,
24644        );
24645        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24646
24647        Some(Bounds {
24648            origin: element_bounds.origin + point(x, y),
24649            size: size(em_width, line_height),
24650        })
24651    }
24652
24653    fn character_index_for_point(
24654        &mut self,
24655        point: gpui::Point<Pixels>,
24656        _window: &mut Window,
24657        _cx: &mut Context<Self>,
24658    ) -> Option<usize> {
24659        let position_map = self.last_position_map.as_ref()?;
24660        if !position_map.text_hitbox.contains(&point) {
24661            return None;
24662        }
24663        let display_point = position_map.point_for_position(point).previous_valid;
24664        let anchor = position_map
24665            .snapshot
24666            .display_point_to_anchor(display_point, Bias::Left);
24667        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24668        Some(utf16_offset.0.0)
24669    }
24670
24671    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24672        self.input_enabled
24673    }
24674}
24675
24676trait SelectionExt {
24677    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24678    fn spanned_rows(
24679        &self,
24680        include_end_if_at_line_start: bool,
24681        map: &DisplaySnapshot,
24682    ) -> Range<MultiBufferRow>;
24683}
24684
24685impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24686    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24687        let start = self
24688            .start
24689            .to_point(map.buffer_snapshot())
24690            .to_display_point(map);
24691        let end = self
24692            .end
24693            .to_point(map.buffer_snapshot())
24694            .to_display_point(map);
24695        if self.reversed {
24696            end..start
24697        } else {
24698            start..end
24699        }
24700    }
24701
24702    fn spanned_rows(
24703        &self,
24704        include_end_if_at_line_start: bool,
24705        map: &DisplaySnapshot,
24706    ) -> Range<MultiBufferRow> {
24707        let start = self.start.to_point(map.buffer_snapshot());
24708        let mut end = self.end.to_point(map.buffer_snapshot());
24709        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24710            end.row -= 1;
24711        }
24712
24713        let buffer_start = map.prev_line_boundary(start).0;
24714        let buffer_end = map.next_line_boundary(end).0;
24715        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24716    }
24717}
24718
24719impl<T: InvalidationRegion> InvalidationStack<T> {
24720    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24721    where
24722        S: Clone + ToOffset,
24723    {
24724        while let Some(region) = self.last() {
24725            let all_selections_inside_invalidation_ranges =
24726                if selections.len() == region.ranges().len() {
24727                    selections
24728                        .iter()
24729                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24730                        .all(|(selection, invalidation_range)| {
24731                            let head = selection.head().to_offset(buffer);
24732                            invalidation_range.start <= head && invalidation_range.end >= head
24733                        })
24734                } else {
24735                    false
24736                };
24737
24738            if all_selections_inside_invalidation_ranges {
24739                break;
24740            } else {
24741                self.pop();
24742            }
24743        }
24744    }
24745}
24746
24747impl<T> Default for InvalidationStack<T> {
24748    fn default() -> Self {
24749        Self(Default::default())
24750    }
24751}
24752
24753impl<T> Deref for InvalidationStack<T> {
24754    type Target = Vec<T>;
24755
24756    fn deref(&self) -> &Self::Target {
24757        &self.0
24758    }
24759}
24760
24761impl<T> DerefMut for InvalidationStack<T> {
24762    fn deref_mut(&mut self) -> &mut Self::Target {
24763        &mut self.0
24764    }
24765}
24766
24767impl InvalidationRegion for SnippetState {
24768    fn ranges(&self) -> &[Range<Anchor>] {
24769        &self.ranges[self.active_index]
24770    }
24771}
24772
24773fn edit_prediction_edit_text(
24774    current_snapshot: &BufferSnapshot,
24775    edits: &[(Range<Anchor>, impl AsRef<str>)],
24776    edit_preview: &EditPreview,
24777    include_deletions: bool,
24778    cx: &App,
24779) -> HighlightedText {
24780    let edits = edits
24781        .iter()
24782        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24783        .collect::<Vec<_>>();
24784
24785    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24786}
24787
24788fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24789    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24790    // Just show the raw edit text with basic styling
24791    let mut text = String::new();
24792    let mut highlights = Vec::new();
24793
24794    let insertion_highlight_style = HighlightStyle {
24795        color: Some(cx.theme().colors().text),
24796        ..Default::default()
24797    };
24798
24799    for (_, edit_text) in edits {
24800        let start_offset = text.len();
24801        text.push_str(edit_text);
24802        let end_offset = text.len();
24803
24804        if start_offset < end_offset {
24805            highlights.push((start_offset..end_offset, insertion_highlight_style));
24806        }
24807    }
24808
24809    HighlightedText {
24810        text: text.into(),
24811        highlights,
24812    }
24813}
24814
24815pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24816    match severity {
24817        lsp::DiagnosticSeverity::ERROR => colors.error,
24818        lsp::DiagnosticSeverity::WARNING => colors.warning,
24819        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24820        lsp::DiagnosticSeverity::HINT => colors.info,
24821        _ => colors.ignored,
24822    }
24823}
24824
24825pub fn styled_runs_for_code_label<'a>(
24826    label: &'a CodeLabel,
24827    syntax_theme: &'a theme::SyntaxTheme,
24828) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24829    let fade_out = HighlightStyle {
24830        fade_out: Some(0.35),
24831        ..Default::default()
24832    };
24833
24834    let mut prev_end = label.filter_range.end;
24835    label
24836        .runs
24837        .iter()
24838        .enumerate()
24839        .flat_map(move |(ix, (range, highlight_id))| {
24840            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24841                style
24842            } else {
24843                return Default::default();
24844            };
24845            let muted_style = style.highlight(fade_out);
24846
24847            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24848            if range.start >= label.filter_range.end {
24849                if range.start > prev_end {
24850                    runs.push((prev_end..range.start, fade_out));
24851                }
24852                runs.push((range.clone(), muted_style));
24853            } else if range.end <= label.filter_range.end {
24854                runs.push((range.clone(), style));
24855            } else {
24856                runs.push((range.start..label.filter_range.end, style));
24857                runs.push((label.filter_range.end..range.end, muted_style));
24858            }
24859            prev_end = cmp::max(prev_end, range.end);
24860
24861            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24862                runs.push((prev_end..label.text.len(), fade_out));
24863            }
24864
24865            runs
24866        })
24867}
24868
24869pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24870    let mut prev_index = 0;
24871    let mut prev_codepoint: Option<char> = None;
24872    text.char_indices()
24873        .chain([(text.len(), '\0')])
24874        .filter_map(move |(index, codepoint)| {
24875            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24876            let is_boundary = index == text.len()
24877                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24878                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24879            if is_boundary {
24880                let chunk = &text[prev_index..index];
24881                prev_index = index;
24882                Some(chunk)
24883            } else {
24884                None
24885            }
24886        })
24887}
24888
24889/// Given a string of text immediately before the cursor, iterates over possible
24890/// strings a snippet could match to. More precisely: returns an iterator over
24891/// suffixes of `text` created by splitting at word boundaries (before & after
24892/// every non-word character).
24893///
24894/// Shorter suffixes are returned first.
24895pub(crate) fn snippet_candidate_suffixes(
24896    text: &str,
24897    is_word_char: impl Fn(char) -> bool,
24898) -> impl std::iter::Iterator<Item = &str> {
24899    let mut prev_index = text.len();
24900    let mut prev_codepoint = None;
24901    text.char_indices()
24902        .rev()
24903        .chain([(0, '\0')])
24904        .filter_map(move |(index, codepoint)| {
24905            let prev_index = std::mem::replace(&mut prev_index, index);
24906            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24907            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
24908                None
24909            } else {
24910                let chunk = &text[prev_index..]; // go to end of string
24911                Some(chunk)
24912            }
24913        })
24914}
24915
24916pub trait RangeToAnchorExt: Sized {
24917    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24918
24919    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24920        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24921        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24922    }
24923}
24924
24925impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24926    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24927        let start_offset = self.start.to_offset(snapshot);
24928        let end_offset = self.end.to_offset(snapshot);
24929        if start_offset == end_offset {
24930            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24931        } else {
24932            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24933        }
24934    }
24935}
24936
24937pub trait RowExt {
24938    fn as_f64(&self) -> f64;
24939
24940    fn next_row(&self) -> Self;
24941
24942    fn previous_row(&self) -> Self;
24943
24944    fn minus(&self, other: Self) -> u32;
24945}
24946
24947impl RowExt for DisplayRow {
24948    fn as_f64(&self) -> f64 {
24949        self.0 as _
24950    }
24951
24952    fn next_row(&self) -> Self {
24953        Self(self.0 + 1)
24954    }
24955
24956    fn previous_row(&self) -> Self {
24957        Self(self.0.saturating_sub(1))
24958    }
24959
24960    fn minus(&self, other: Self) -> u32 {
24961        self.0 - other.0
24962    }
24963}
24964
24965impl RowExt for MultiBufferRow {
24966    fn as_f64(&self) -> f64 {
24967        self.0 as _
24968    }
24969
24970    fn next_row(&self) -> Self {
24971        Self(self.0 + 1)
24972    }
24973
24974    fn previous_row(&self) -> Self {
24975        Self(self.0.saturating_sub(1))
24976    }
24977
24978    fn minus(&self, other: Self) -> u32 {
24979        self.0 - other.0
24980    }
24981}
24982
24983trait RowRangeExt {
24984    type Row;
24985
24986    fn len(&self) -> usize;
24987
24988    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24989}
24990
24991impl RowRangeExt for Range<MultiBufferRow> {
24992    type Row = MultiBufferRow;
24993
24994    fn len(&self) -> usize {
24995        (self.end.0 - self.start.0) as usize
24996    }
24997
24998    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24999        (self.start.0..self.end.0).map(MultiBufferRow)
25000    }
25001}
25002
25003impl RowRangeExt for Range<DisplayRow> {
25004    type Row = DisplayRow;
25005
25006    fn len(&self) -> usize {
25007        (self.end.0 - self.start.0) as usize
25008    }
25009
25010    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25011        (self.start.0..self.end.0).map(DisplayRow)
25012    }
25013}
25014
25015/// If select range has more than one line, we
25016/// just point the cursor to range.start.
25017fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25018    if range.start.row == range.end.row {
25019        range
25020    } else {
25021        range.start..range.start
25022    }
25023}
25024pub struct KillRing(ClipboardItem);
25025impl Global for KillRing {}
25026
25027const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25028
25029enum BreakpointPromptEditAction {
25030    Log,
25031    Condition,
25032    HitCondition,
25033}
25034
25035struct BreakpointPromptEditor {
25036    pub(crate) prompt: Entity<Editor>,
25037    editor: WeakEntity<Editor>,
25038    breakpoint_anchor: Anchor,
25039    breakpoint: Breakpoint,
25040    edit_action: BreakpointPromptEditAction,
25041    block_ids: HashSet<CustomBlockId>,
25042    editor_margins: Arc<Mutex<EditorMargins>>,
25043    _subscriptions: Vec<Subscription>,
25044}
25045
25046impl BreakpointPromptEditor {
25047    const MAX_LINES: u8 = 4;
25048
25049    fn new(
25050        editor: WeakEntity<Editor>,
25051        breakpoint_anchor: Anchor,
25052        breakpoint: Breakpoint,
25053        edit_action: BreakpointPromptEditAction,
25054        window: &mut Window,
25055        cx: &mut Context<Self>,
25056    ) -> Self {
25057        let base_text = match edit_action {
25058            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25059            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25060            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25061        }
25062        .map(|msg| msg.to_string())
25063        .unwrap_or_default();
25064
25065        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25066        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25067
25068        let prompt = cx.new(|cx| {
25069            let mut prompt = Editor::new(
25070                EditorMode::AutoHeight {
25071                    min_lines: 1,
25072                    max_lines: Some(Self::MAX_LINES as usize),
25073                },
25074                buffer,
25075                None,
25076                window,
25077                cx,
25078            );
25079            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25080            prompt.set_show_cursor_when_unfocused(false, cx);
25081            prompt.set_placeholder_text(
25082                match edit_action {
25083                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25084                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25085                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25086                },
25087                window,
25088                cx,
25089            );
25090
25091            prompt
25092        });
25093
25094        Self {
25095            prompt,
25096            editor,
25097            breakpoint_anchor,
25098            breakpoint,
25099            edit_action,
25100            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25101            block_ids: Default::default(),
25102            _subscriptions: vec![],
25103        }
25104    }
25105
25106    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25107        self.block_ids.extend(block_ids)
25108    }
25109
25110    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25111        if let Some(editor) = self.editor.upgrade() {
25112            let message = self
25113                .prompt
25114                .read(cx)
25115                .buffer
25116                .read(cx)
25117                .as_singleton()
25118                .expect("A multi buffer in breakpoint prompt isn't possible")
25119                .read(cx)
25120                .as_rope()
25121                .to_string();
25122
25123            editor.update(cx, |editor, cx| {
25124                editor.edit_breakpoint_at_anchor(
25125                    self.breakpoint_anchor,
25126                    self.breakpoint.clone(),
25127                    match self.edit_action {
25128                        BreakpointPromptEditAction::Log => {
25129                            BreakpointEditAction::EditLogMessage(message.into())
25130                        }
25131                        BreakpointPromptEditAction::Condition => {
25132                            BreakpointEditAction::EditCondition(message.into())
25133                        }
25134                        BreakpointPromptEditAction::HitCondition => {
25135                            BreakpointEditAction::EditHitCondition(message.into())
25136                        }
25137                    },
25138                    cx,
25139                );
25140
25141                editor.remove_blocks(self.block_ids.clone(), None, cx);
25142                cx.focus_self(window);
25143            });
25144        }
25145    }
25146
25147    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25148        self.editor
25149            .update(cx, |editor, cx| {
25150                editor.remove_blocks(self.block_ids.clone(), None, cx);
25151                window.focus(&editor.focus_handle);
25152            })
25153            .log_err();
25154    }
25155
25156    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25157        let settings = ThemeSettings::get_global(cx);
25158        let text_style = TextStyle {
25159            color: if self.prompt.read(cx).read_only(cx) {
25160                cx.theme().colors().text_disabled
25161            } else {
25162                cx.theme().colors().text
25163            },
25164            font_family: settings.buffer_font.family.clone(),
25165            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25166            font_size: settings.buffer_font_size(cx).into(),
25167            font_weight: settings.buffer_font.weight,
25168            line_height: relative(settings.buffer_line_height.value()),
25169            ..Default::default()
25170        };
25171        EditorElement::new(
25172            &self.prompt,
25173            EditorStyle {
25174                background: cx.theme().colors().editor_background,
25175                local_player: cx.theme().players().local(),
25176                text: text_style,
25177                ..Default::default()
25178            },
25179        )
25180    }
25181}
25182
25183impl Render for BreakpointPromptEditor {
25184    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25185        let editor_margins = *self.editor_margins.lock();
25186        let gutter_dimensions = editor_margins.gutter;
25187        h_flex()
25188            .key_context("Editor")
25189            .bg(cx.theme().colors().editor_background)
25190            .border_y_1()
25191            .border_color(cx.theme().status().info_border)
25192            .size_full()
25193            .py(window.line_height() / 2.5)
25194            .on_action(cx.listener(Self::confirm))
25195            .on_action(cx.listener(Self::cancel))
25196            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25197            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25198    }
25199}
25200
25201impl Focusable for BreakpointPromptEditor {
25202    fn focus_handle(&self, cx: &App) -> FocusHandle {
25203        self.prompt.focus_handle(cx)
25204    }
25205}
25206
25207fn all_edits_insertions_or_deletions(
25208    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25209    snapshot: &MultiBufferSnapshot,
25210) -> bool {
25211    let mut all_insertions = true;
25212    let mut all_deletions = true;
25213
25214    for (range, new_text) in edits.iter() {
25215        let range_is_empty = range.to_offset(snapshot).is_empty();
25216        let text_is_empty = new_text.is_empty();
25217
25218        if range_is_empty != text_is_empty {
25219            if range_is_empty {
25220                all_deletions = false;
25221            } else {
25222                all_insertions = false;
25223            }
25224        } else {
25225            return false;
25226        }
25227
25228        if !all_insertions && !all_deletions {
25229            return false;
25230        }
25231    }
25232    all_insertions || all_deletions
25233}
25234
25235struct MissingEditPredictionKeybindingTooltip;
25236
25237impl Render for MissingEditPredictionKeybindingTooltip {
25238    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25239        ui::tooltip_container(cx, |container, cx| {
25240            container
25241                .flex_shrink_0()
25242                .max_w_80()
25243                .min_h(rems_from_px(124.))
25244                .justify_between()
25245                .child(
25246                    v_flex()
25247                        .flex_1()
25248                        .text_ui_sm(cx)
25249                        .child(Label::new("Conflict with Accept Keybinding"))
25250                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25251                )
25252                .child(
25253                    h_flex()
25254                        .pb_1()
25255                        .gap_1()
25256                        .items_end()
25257                        .w_full()
25258                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25259                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25260                        }))
25261                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25262                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25263                        })),
25264                )
25265        })
25266    }
25267}
25268
25269#[derive(Debug, Clone, Copy, PartialEq)]
25270pub struct LineHighlight {
25271    pub background: Background,
25272    pub border: Option<gpui::Hsla>,
25273    pub include_gutter: bool,
25274    pub type_id: Option<TypeId>,
25275}
25276
25277struct LineManipulationResult {
25278    pub new_text: String,
25279    pub line_count_before: usize,
25280    pub line_count_after: usize,
25281}
25282
25283fn render_diff_hunk_controls(
25284    row: u32,
25285    status: &DiffHunkStatus,
25286    hunk_range: Range<Anchor>,
25287    is_created_file: bool,
25288    line_height: Pixels,
25289    editor: &Entity<Editor>,
25290    _window: &mut Window,
25291    cx: &mut App,
25292) -> AnyElement {
25293    h_flex()
25294        .h(line_height)
25295        .mr_1()
25296        .gap_1()
25297        .px_0p5()
25298        .pb_1()
25299        .border_x_1()
25300        .border_b_1()
25301        .border_color(cx.theme().colors().border_variant)
25302        .rounded_b_lg()
25303        .bg(cx.theme().colors().editor_background)
25304        .gap_1()
25305        .block_mouse_except_scroll()
25306        .shadow_md()
25307        .child(if status.has_secondary_hunk() {
25308            Button::new(("stage", row as u64), "Stage")
25309                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25310                .tooltip({
25311                    let focus_handle = editor.focus_handle(cx);
25312                    move |_window, cx| {
25313                        Tooltip::for_action_in(
25314                            "Stage Hunk",
25315                            &::git::ToggleStaged,
25316                            &focus_handle,
25317                            cx,
25318                        )
25319                    }
25320                })
25321                .on_click({
25322                    let editor = editor.clone();
25323                    move |_event, _window, cx| {
25324                        editor.update(cx, |editor, cx| {
25325                            editor.stage_or_unstage_diff_hunks(
25326                                true,
25327                                vec![hunk_range.start..hunk_range.start],
25328                                cx,
25329                            );
25330                        });
25331                    }
25332                })
25333        } else {
25334            Button::new(("unstage", row as u64), "Unstage")
25335                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25336                .tooltip({
25337                    let focus_handle = editor.focus_handle(cx);
25338                    move |_window, cx| {
25339                        Tooltip::for_action_in(
25340                            "Unstage Hunk",
25341                            &::git::ToggleStaged,
25342                            &focus_handle,
25343                            cx,
25344                        )
25345                    }
25346                })
25347                .on_click({
25348                    let editor = editor.clone();
25349                    move |_event, _window, cx| {
25350                        editor.update(cx, |editor, cx| {
25351                            editor.stage_or_unstage_diff_hunks(
25352                                false,
25353                                vec![hunk_range.start..hunk_range.start],
25354                                cx,
25355                            );
25356                        });
25357                    }
25358                })
25359        })
25360        .child(
25361            Button::new(("restore", row as u64), "Restore")
25362                .tooltip({
25363                    let focus_handle = editor.focus_handle(cx);
25364                    move |_window, cx| {
25365                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25366                    }
25367                })
25368                .on_click({
25369                    let editor = editor.clone();
25370                    move |_event, window, cx| {
25371                        editor.update(cx, |editor, cx| {
25372                            let snapshot = editor.snapshot(window, cx);
25373                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25374                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25375                        });
25376                    }
25377                })
25378                .disabled(is_created_file),
25379        )
25380        .when(
25381            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25382            |el| {
25383                el.child(
25384                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25385                        .shape(IconButtonShape::Square)
25386                        .icon_size(IconSize::Small)
25387                        // .disabled(!has_multiple_hunks)
25388                        .tooltip({
25389                            let focus_handle = editor.focus_handle(cx);
25390                            move |_window, cx| {
25391                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25392                            }
25393                        })
25394                        .on_click({
25395                            let editor = editor.clone();
25396                            move |_event, window, cx| {
25397                                editor.update(cx, |editor, cx| {
25398                                    let snapshot = editor.snapshot(window, cx);
25399                                    let position =
25400                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25401                                    editor.go_to_hunk_before_or_after_position(
25402                                        &snapshot,
25403                                        position,
25404                                        Direction::Next,
25405                                        window,
25406                                        cx,
25407                                    );
25408                                    editor.expand_selected_diff_hunks(cx);
25409                                });
25410                            }
25411                        }),
25412                )
25413                .child(
25414                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25415                        .shape(IconButtonShape::Square)
25416                        .icon_size(IconSize::Small)
25417                        // .disabled(!has_multiple_hunks)
25418                        .tooltip({
25419                            let focus_handle = editor.focus_handle(cx);
25420                            move |_window, cx| {
25421                                Tooltip::for_action_in(
25422                                    "Previous Hunk",
25423                                    &GoToPreviousHunk,
25424                                    &focus_handle,
25425                                    cx,
25426                                )
25427                            }
25428                        })
25429                        .on_click({
25430                            let editor = editor.clone();
25431                            move |_event, window, cx| {
25432                                editor.update(cx, |editor, cx| {
25433                                    let snapshot = editor.snapshot(window, cx);
25434                                    let point =
25435                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25436                                    editor.go_to_hunk_before_or_after_position(
25437                                        &snapshot,
25438                                        point,
25439                                        Direction::Prev,
25440                                        window,
25441                                        cx,
25442                                    );
25443                                    editor.expand_selected_diff_hunks(cx);
25444                                });
25445                            }
25446                        }),
25447                )
25448            },
25449        )
25450        .into_any_element()
25451}
25452
25453pub fn multibuffer_context_lines(cx: &App) -> u32 {
25454    EditorSettings::try_get(cx)
25455        .map(|settings| settings.excerpt_context_lines)
25456        .unwrap_or(2)
25457        .min(32)
25458}