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;
   15pub mod 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;
   39mod split;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod edit_prediction_tests;
   46#[cfg(test)]
   47mod editor_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   54pub use edit_prediction_types::Direction;
   55pub use editor_settings::{
   56    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   57    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61};
   62pub use git::blame::BlameRenderer;
   63pub use hover_popover::hover_markdown_style;
   64pub use inlays::Inlay;
   65pub use items::MAX_TAB_TITLE_LEN;
   66pub use lsp::CompletionContext;
   67pub use lsp_ext::lsp_tasks;
   68pub use multi_buffer::{
   69    Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   70    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   71    ToPoint,
   72};
   73pub use split::SplittableEditor;
   74pub use text::Bias;
   75
   76use ::git::{
   77    Restore,
   78    blame::{BlameEntry, ParsedCommitMessage},
   79    status::FileStatus,
   80};
   81use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   82use anyhow::{Context as _, Result, anyhow, bail};
   83use blink_manager::BlinkManager;
   84use buffer_diff::DiffHunkStatus;
   85use client::{Collaborator, ParticipantIndex, parse_zed_link};
   86use clock::ReplicaId;
   87use code_context_menus::{
   88    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   89    CompletionsMenu, ContextMenuOrigin,
   90};
   91use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   92use convert_case::{Case, Casing};
   93use dap::TelemetrySpawnLocation;
   94use display_map::*;
   95use edit_prediction_types::{EditPredictionDelegate, EditPredictionDelegateHandle};
   96use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   97use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   98use futures::{
   99    FutureExt, StreamExt as _,
  100    future::{self, Shared, join},
  101    stream::FuturesUnordered,
  102};
  103use fuzzy::{StringMatch, StringMatchCandidate};
  104use git::blame::{GitBlame, GlobalBlameRenderer};
  105use gpui::{
  106    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  107    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  108    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  109    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  110    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, PressureStage,
  111    Render, ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, TextRun,
  112    TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle,
  113    WeakEntity, WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative,
  114    size,
  115};
  116use hover_links::{HoverLink, HoveredLinkState, find_file};
  117use hover_popover::{HoverState, hide_hover};
  118use indent_guides::ActiveIndentGuidesState;
  119use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  120use itertools::{Either, Itertools};
  121use language::{
  122    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  123    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  124    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  125    IndentSize, Language, LanguageName, LanguageRegistry, OffsetRangeExt, OutlineItem, Point,
  126    Runnable, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  127    language_settings::{
  128        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  129        all_language_settings, language_settings,
  130    },
  131    point_from_lsp, point_to_lsp, text_diff_with_options,
  132};
  133use linked_editing_ranges::refresh_linked_ranges;
  134use lsp::{
  135    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  136    LanguageServerId,
  137};
  138use lsp_colors::LspColorData;
  139use markdown::Markdown;
  140use mouse_context_menu::MouseContextMenu;
  141use movement::TextLayoutDetails;
  142use multi_buffer::{
  143    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  144};
  145use parking_lot::Mutex;
  146use persistence::DB;
  147use project::{
  148    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  149    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  150    InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project,
  151    ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  152    debugger::{
  153        breakpoint_store::{
  154            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  155            BreakpointStore, BreakpointStoreEvent,
  156        },
  157        session::{Session, SessionEvent},
  158    },
  159    git_store::GitStoreEvent,
  160    lsp_store::{
  161        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  162        OpenLspBufferHandle,
  163    },
  164    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  165};
  166use rand::seq::SliceRandom;
  167use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  168use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  169use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  170use serde::{Deserialize, Serialize};
  171use settings::{
  172    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  173    update_settings_file,
  174};
  175use smallvec::{SmallVec, smallvec};
  176use snippet::Snippet;
  177use std::{
  178    any::{Any, TypeId},
  179    borrow::Cow,
  180    cell::{OnceCell, RefCell},
  181    cmp::{self, Ordering, Reverse},
  182    collections::hash_map,
  183    iter::{self, Peekable},
  184    mem,
  185    num::NonZeroU32,
  186    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  187    path::{Path, PathBuf},
  188    rc::Rc,
  189    sync::Arc,
  190    time::{Duration, Instant},
  191};
  192use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  193use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  194use theme::{
  195    AccentColors, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  196    observe_buffer_font_size_adjustment,
  197};
  198use ui::{
  199    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  200    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  201};
  202use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  203use workspace::{
  204    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  205    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  206    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  207    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  208    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  209    searchable::SearchEvent,
  210};
  211
  212use crate::{
  213    code_context_menus::CompletionsMenuSource,
  214    editor_settings::MultiCursorModifier,
  215    hover_links::{find_url, find_url_from_range},
  216    inlays::{
  217        InlineValueCache,
  218        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  219    },
  220    scroll::{ScrollOffset, ScrollPixelOffset},
  221    selections_collection::resolve_selections_wrapping_blocks,
  222    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  223};
  224
  225pub const FILE_HEADER_HEIGHT: u32 = 2;
  226pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  227const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  228const MAX_LINE_LEN: usize = 1024;
  229const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  230const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  231pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  232#[doc(hidden)]
  233pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  234pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  235
  236pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  237pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  238pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  239pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  240
  241pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  242pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  243pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  244
  245pub type RenderDiffHunkControlsFn = Arc<
  246    dyn Fn(
  247        u32,
  248        &DiffHunkStatus,
  249        Range<Anchor>,
  250        bool,
  251        Pixels,
  252        &Entity<Editor>,
  253        &mut Window,
  254        &mut App,
  255    ) -> AnyElement,
  256>;
  257
  258enum ReportEditorEvent {
  259    Saved { auto_saved: bool },
  260    EditorOpened,
  261    Closed,
  262}
  263
  264impl ReportEditorEvent {
  265    pub fn event_type(&self) -> &'static str {
  266        match self {
  267            Self::Saved { .. } => "Editor Saved",
  268            Self::EditorOpened => "Editor Opened",
  269            Self::Closed => "Editor Closed",
  270        }
  271    }
  272}
  273
  274pub enum ActiveDebugLine {}
  275pub enum DebugStackFrameLine {}
  276enum DocumentHighlightRead {}
  277enum DocumentHighlightWrite {}
  278enum InputComposition {}
  279pub enum PendingInput {}
  280enum SelectedTextHighlight {}
  281
  282pub enum ConflictsOuter {}
  283pub enum ConflictsOurs {}
  284pub enum ConflictsTheirs {}
  285pub enum ConflictsOursMarker {}
  286pub enum ConflictsTheirsMarker {}
  287
  288pub struct HunkAddedColor;
  289pub struct HunkRemovedColor;
  290
  291#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  292pub enum Navigated {
  293    Yes,
  294    No,
  295}
  296
  297impl Navigated {
  298    pub fn from_bool(yes: bool) -> Navigated {
  299        if yes { Navigated::Yes } else { Navigated::No }
  300    }
  301}
  302
  303#[derive(Debug, Clone, PartialEq, Eq)]
  304enum DisplayDiffHunk {
  305    Folded {
  306        display_row: DisplayRow,
  307    },
  308    Unfolded {
  309        is_created_file: bool,
  310        diff_base_byte_range: Range<usize>,
  311        display_row_range: Range<DisplayRow>,
  312        multi_buffer_range: Range<Anchor>,
  313        status: DiffHunkStatus,
  314        word_diffs: Vec<Range<MultiBufferOffset>>,
  315    },
  316}
  317
  318pub enum HideMouseCursorOrigin {
  319    TypingAction,
  320    MovementAction,
  321}
  322
  323pub fn init(cx: &mut App) {
  324    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  325
  326    workspace::register_project_item::<Editor>(cx);
  327    workspace::FollowableViewRegistry::register::<Editor>(cx);
  328    workspace::register_serializable_item::<Editor>(cx);
  329
  330    cx.observe_new(
  331        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  332            workspace.register_action(Editor::new_file);
  333            workspace.register_action(Editor::new_file_split);
  334            workspace.register_action(Editor::new_file_vertical);
  335            workspace.register_action(Editor::new_file_horizontal);
  336            workspace.register_action(Editor::cancel_language_server_work);
  337            workspace.register_action(Editor::toggle_focus);
  338        },
  339    )
  340    .detach();
  341
  342    cx.on_action(move |_: &workspace::NewFile, cx| {
  343        let app_state = workspace::AppState::global(cx);
  344        if let Some(app_state) = app_state.upgrade() {
  345            workspace::open_new(
  346                Default::default(),
  347                app_state,
  348                cx,
  349                |workspace, window, cx| {
  350                    Editor::new_file(workspace, &Default::default(), window, cx)
  351                },
  352            )
  353            .detach();
  354        }
  355    })
  356    .on_action(move |_: &workspace::NewWindow, cx| {
  357        let app_state = workspace::AppState::global(cx);
  358        if let Some(app_state) = app_state.upgrade() {
  359            workspace::open_new(
  360                Default::default(),
  361                app_state,
  362                cx,
  363                |workspace, window, cx| {
  364                    cx.activate(true);
  365                    Editor::new_file(workspace, &Default::default(), window, cx)
  366                },
  367            )
  368            .detach();
  369        }
  370    });
  371}
  372
  373pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  374    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  375}
  376
  377pub trait DiagnosticRenderer {
  378    fn render_group(
  379        &self,
  380        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  381        buffer_id: BufferId,
  382        snapshot: EditorSnapshot,
  383        editor: WeakEntity<Editor>,
  384        language_registry: Option<Arc<LanguageRegistry>>,
  385        cx: &mut App,
  386    ) -> Vec<BlockProperties<Anchor>>;
  387
  388    fn render_hover(
  389        &self,
  390        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  391        range: Range<Point>,
  392        buffer_id: BufferId,
  393        language_registry: Option<Arc<LanguageRegistry>>,
  394        cx: &mut App,
  395    ) -> Option<Entity<markdown::Markdown>>;
  396
  397    fn open_link(
  398        &self,
  399        editor: &mut Editor,
  400        link: SharedString,
  401        window: &mut Window,
  402        cx: &mut Context<Editor>,
  403    );
  404}
  405
  406pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  407
  408impl GlobalDiagnosticRenderer {
  409    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  410        cx.try_global::<Self>().map(|g| g.0.clone())
  411    }
  412}
  413
  414impl gpui::Global for GlobalDiagnosticRenderer {}
  415pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  416    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  417}
  418
  419pub struct SearchWithinRange;
  420
  421trait InvalidationRegion {
  422    fn ranges(&self) -> &[Range<Anchor>];
  423}
  424
  425#[derive(Clone, Debug, PartialEq)]
  426pub enum SelectPhase {
  427    Begin {
  428        position: DisplayPoint,
  429        add: bool,
  430        click_count: usize,
  431    },
  432    BeginColumnar {
  433        position: DisplayPoint,
  434        reset: bool,
  435        mode: ColumnarMode,
  436        goal_column: u32,
  437    },
  438    Extend {
  439        position: DisplayPoint,
  440        click_count: usize,
  441    },
  442    Update {
  443        position: DisplayPoint,
  444        goal_column: u32,
  445        scroll_delta: gpui::Point<f32>,
  446    },
  447    End,
  448}
  449
  450#[derive(Clone, Debug, PartialEq)]
  451pub enum ColumnarMode {
  452    FromMouse,
  453    FromSelection,
  454}
  455
  456#[derive(Clone, Debug)]
  457pub enum SelectMode {
  458    Character,
  459    Word(Range<Anchor>),
  460    Line(Range<Anchor>),
  461    All,
  462}
  463
  464#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  465pub enum SizingBehavior {
  466    /// The editor will layout itself using `size_full` and will include the vertical
  467    /// scroll margin as requested by user settings.
  468    #[default]
  469    Default,
  470    /// The editor will layout itself using `size_full`, but will not have any
  471    /// vertical overscroll.
  472    ExcludeOverscrollMargin,
  473    /// The editor will request a vertical size according to its content and will be
  474    /// layouted without a vertical scroll margin.
  475    SizeByContent,
  476}
  477
  478#[derive(Clone, PartialEq, Eq, Debug)]
  479pub enum EditorMode {
  480    SingleLine,
  481    AutoHeight {
  482        min_lines: usize,
  483        max_lines: Option<usize>,
  484    },
  485    Full {
  486        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  487        scale_ui_elements_with_buffer_font_size: bool,
  488        /// When set to `true`, the editor will render a background for the active line.
  489        show_active_line_background: bool,
  490        /// Determines the sizing behavior for this editor
  491        sizing_behavior: SizingBehavior,
  492    },
  493    Minimap {
  494        parent: WeakEntity<Editor>,
  495    },
  496}
  497
  498impl EditorMode {
  499    pub fn full() -> Self {
  500        Self::Full {
  501            scale_ui_elements_with_buffer_font_size: true,
  502            show_active_line_background: true,
  503            sizing_behavior: SizingBehavior::Default,
  504        }
  505    }
  506
  507    #[inline]
  508    pub fn is_full(&self) -> bool {
  509        matches!(self, Self::Full { .. })
  510    }
  511
  512    #[inline]
  513    pub fn is_single_line(&self) -> bool {
  514        matches!(self, Self::SingleLine { .. })
  515    }
  516
  517    #[inline]
  518    fn is_minimap(&self) -> bool {
  519        matches!(self, Self::Minimap { .. })
  520    }
  521}
  522
  523#[derive(Copy, Clone, Debug)]
  524pub enum SoftWrap {
  525    /// Prefer not to wrap at all.
  526    ///
  527    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  528    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  529    GitDiff,
  530    /// Prefer a single line generally, unless an overly long line is encountered.
  531    None,
  532    /// Soft wrap lines that exceed the editor width.
  533    EditorWidth,
  534    /// Soft wrap lines at the preferred line length.
  535    Column(u32),
  536    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  537    Bounded(u32),
  538}
  539
  540#[derive(Clone)]
  541pub struct EditorStyle {
  542    pub background: Hsla,
  543    pub border: Hsla,
  544    pub local_player: PlayerColor,
  545    pub text: TextStyle,
  546    pub scrollbar_width: Pixels,
  547    pub syntax: Arc<SyntaxTheme>,
  548    pub status: StatusColors,
  549    pub inlay_hints_style: HighlightStyle,
  550    pub edit_prediction_styles: EditPredictionStyles,
  551    pub unnecessary_code_fade: f32,
  552    pub show_underlines: bool,
  553}
  554
  555impl Default for EditorStyle {
  556    fn default() -> Self {
  557        Self {
  558            background: Hsla::default(),
  559            border: Hsla::default(),
  560            local_player: PlayerColor::default(),
  561            text: TextStyle::default(),
  562            scrollbar_width: Pixels::default(),
  563            syntax: Default::default(),
  564            // HACK: Status colors don't have a real default.
  565            // We should look into removing the status colors from the editor
  566            // style and retrieve them directly from the theme.
  567            status: StatusColors::dark(),
  568            inlay_hints_style: HighlightStyle::default(),
  569            edit_prediction_styles: EditPredictionStyles {
  570                insertion: HighlightStyle::default(),
  571                whitespace: HighlightStyle::default(),
  572            },
  573            unnecessary_code_fade: Default::default(),
  574            show_underlines: true,
  575        }
  576    }
  577}
  578
  579pub fn make_inlay_hints_style(cx: &App) -> HighlightStyle {
  580    let show_background = language_settings::language_settings(None, None, cx)
  581        .inlay_hints
  582        .show_background;
  583
  584    let mut style = cx.theme().syntax().get("hint");
  585
  586    if style.color.is_none() {
  587        style.color = Some(cx.theme().status().hint);
  588    }
  589
  590    if !show_background {
  591        style.background_color = None;
  592        return style;
  593    }
  594
  595    if style.background_color.is_none() {
  596        style.background_color = Some(cx.theme().status().hint_background);
  597    }
  598
  599    style
  600}
  601
  602pub fn make_suggestion_styles(cx: &App) -> EditPredictionStyles {
  603    EditPredictionStyles {
  604        insertion: HighlightStyle {
  605            color: Some(cx.theme().status().predictive),
  606            ..HighlightStyle::default()
  607        },
  608        whitespace: HighlightStyle {
  609            background_color: Some(cx.theme().status().created_background),
  610            ..HighlightStyle::default()
  611        },
  612    }
  613}
  614
  615type CompletionId = usize;
  616
  617pub(crate) enum EditDisplayMode {
  618    TabAccept,
  619    DiffPopover,
  620    Inline,
  621}
  622
  623enum EditPrediction {
  624    Edit {
  625        edits: Vec<(Range<Anchor>, Arc<str>)>,
  626        edit_preview: Option<EditPreview>,
  627        display_mode: EditDisplayMode,
  628        snapshot: BufferSnapshot,
  629    },
  630    /// Move to a specific location in the active editor
  631    MoveWithin {
  632        target: Anchor,
  633        snapshot: BufferSnapshot,
  634    },
  635    /// Move to a specific location in a different editor (not the active one)
  636    MoveOutside {
  637        target: language::Anchor,
  638        snapshot: BufferSnapshot,
  639    },
  640}
  641
  642struct EditPredictionState {
  643    inlay_ids: Vec<InlayId>,
  644    completion: EditPrediction,
  645    completion_id: Option<SharedString>,
  646    invalidation_range: Option<Range<Anchor>>,
  647}
  648
  649enum EditPredictionSettings {
  650    Disabled,
  651    Enabled {
  652        show_in_menu: bool,
  653        preview_requires_modifier: bool,
  654    },
  655}
  656
  657enum EditPredictionHighlight {}
  658
  659#[derive(Debug, Clone)]
  660struct InlineDiagnostic {
  661    message: SharedString,
  662    group_id: usize,
  663    is_primary: bool,
  664    start: Point,
  665    severity: lsp::DiagnosticSeverity,
  666}
  667
  668pub enum MenuEditPredictionsPolicy {
  669    Never,
  670    ByProvider,
  671}
  672
  673pub enum EditPredictionPreview {
  674    /// Modifier is not pressed
  675    Inactive { released_too_fast: bool },
  676    /// Modifier pressed
  677    Active {
  678        since: Instant,
  679        previous_scroll_position: Option<ScrollAnchor>,
  680    },
  681}
  682
  683impl EditPredictionPreview {
  684    pub fn released_too_fast(&self) -> bool {
  685        match self {
  686            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  687            EditPredictionPreview::Active { .. } => false,
  688        }
  689    }
  690
  691    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  692        if let EditPredictionPreview::Active {
  693            previous_scroll_position,
  694            ..
  695        } = self
  696        {
  697            *previous_scroll_position = scroll_position;
  698        }
  699    }
  700}
  701
  702pub struct ContextMenuOptions {
  703    pub min_entries_visible: usize,
  704    pub max_entries_visible: usize,
  705    pub placement: Option<ContextMenuPlacement>,
  706}
  707
  708#[derive(Debug, Clone, PartialEq, Eq)]
  709pub enum ContextMenuPlacement {
  710    Above,
  711    Below,
  712}
  713
  714#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  715struct EditorActionId(usize);
  716
  717impl EditorActionId {
  718    pub fn post_inc(&mut self) -> Self {
  719        let answer = self.0;
  720
  721        *self = Self(answer + 1);
  722
  723        Self(answer)
  724    }
  725}
  726
  727// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  728// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  729
  730type BackgroundHighlight = (
  731    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  732    Arc<[Range<Anchor>]>,
  733);
  734type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  735
  736#[derive(Default)]
  737struct ScrollbarMarkerState {
  738    scrollbar_size: Size<Pixels>,
  739    dirty: bool,
  740    markers: Arc<[PaintQuad]>,
  741    pending_refresh: Option<Task<Result<()>>>,
  742}
  743
  744impl ScrollbarMarkerState {
  745    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  746        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  747    }
  748}
  749
  750#[derive(Clone, Copy, PartialEq, Eq)]
  751pub enum MinimapVisibility {
  752    Disabled,
  753    Enabled {
  754        /// The configuration currently present in the users settings.
  755        setting_configuration: bool,
  756        /// Whether to override the currently set visibility from the users setting.
  757        toggle_override: bool,
  758    },
  759}
  760
  761impl MinimapVisibility {
  762    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  763        if mode.is_full() {
  764            Self::Enabled {
  765                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  766                toggle_override: false,
  767            }
  768        } else {
  769            Self::Disabled
  770        }
  771    }
  772
  773    fn hidden(&self) -> Self {
  774        match *self {
  775            Self::Enabled {
  776                setting_configuration,
  777                ..
  778            } => Self::Enabled {
  779                setting_configuration,
  780                toggle_override: setting_configuration,
  781            },
  782            Self::Disabled => Self::Disabled,
  783        }
  784    }
  785
  786    fn disabled(&self) -> bool {
  787        matches!(*self, Self::Disabled)
  788    }
  789
  790    fn settings_visibility(&self) -> bool {
  791        match *self {
  792            Self::Enabled {
  793                setting_configuration,
  794                ..
  795            } => setting_configuration,
  796            _ => false,
  797        }
  798    }
  799
  800    fn visible(&self) -> bool {
  801        match *self {
  802            Self::Enabled {
  803                setting_configuration,
  804                toggle_override,
  805            } => setting_configuration ^ toggle_override,
  806            _ => false,
  807        }
  808    }
  809
  810    fn toggle_visibility(&self) -> Self {
  811        match *self {
  812            Self::Enabled {
  813                toggle_override,
  814                setting_configuration,
  815            } => Self::Enabled {
  816                setting_configuration,
  817                toggle_override: !toggle_override,
  818            },
  819            Self::Disabled => Self::Disabled,
  820        }
  821    }
  822}
  823
  824#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  825pub enum BufferSerialization {
  826    All,
  827    NonDirtyBuffers,
  828}
  829
  830impl BufferSerialization {
  831    fn new(restore_unsaved_buffers: bool) -> Self {
  832        if restore_unsaved_buffers {
  833            Self::All
  834        } else {
  835            Self::NonDirtyBuffers
  836        }
  837    }
  838}
  839
  840#[derive(Clone, Debug)]
  841struct RunnableTasks {
  842    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  843    offset: multi_buffer::Anchor,
  844    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  845    column: u32,
  846    // Values of all named captures, including those starting with '_'
  847    extra_variables: HashMap<String, String>,
  848    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  849    context_range: Range<BufferOffset>,
  850}
  851
  852impl RunnableTasks {
  853    fn resolve<'a>(
  854        &'a self,
  855        cx: &'a task::TaskContext,
  856    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  857        self.templates.iter().filter_map(|(kind, template)| {
  858            template
  859                .resolve_task(&kind.to_id_base(), cx)
  860                .map(|task| (kind.clone(), task))
  861        })
  862    }
  863}
  864
  865#[derive(Clone)]
  866pub struct ResolvedTasks {
  867    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  868    position: Anchor,
  869}
  870
  871/// Addons allow storing per-editor state in other crates (e.g. Vim)
  872pub trait Addon: 'static {
  873    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  874
  875    fn render_buffer_header_controls(
  876        &self,
  877        _: &ExcerptInfo,
  878        _: &Window,
  879        _: &App,
  880    ) -> Option<AnyElement> {
  881        None
  882    }
  883
  884    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  885        None
  886    }
  887
  888    fn to_any(&self) -> &dyn std::any::Any;
  889
  890    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  891        None
  892    }
  893}
  894
  895struct ChangeLocation {
  896    current: Option<Vec<Anchor>>,
  897    original: Vec<Anchor>,
  898}
  899impl ChangeLocation {
  900    fn locations(&self) -> &[Anchor] {
  901        self.current.as_ref().unwrap_or(&self.original)
  902    }
  903}
  904
  905/// A set of caret positions, registered when the editor was edited.
  906pub struct ChangeList {
  907    changes: Vec<ChangeLocation>,
  908    /// Currently "selected" change.
  909    position: Option<usize>,
  910}
  911
  912impl ChangeList {
  913    pub fn new() -> Self {
  914        Self {
  915            changes: Vec::new(),
  916            position: None,
  917        }
  918    }
  919
  920    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  921    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  922    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  923        if self.changes.is_empty() {
  924            return None;
  925        }
  926
  927        let prev = self.position.unwrap_or(self.changes.len());
  928        let next = if direction == Direction::Prev {
  929            prev.saturating_sub(count)
  930        } else {
  931            (prev + count).min(self.changes.len() - 1)
  932        };
  933        self.position = Some(next);
  934        self.changes.get(next).map(|change| change.locations())
  935    }
  936
  937    /// Adds a new change to the list, resetting the change list position.
  938    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  939        self.position.take();
  940        if let Some(last) = self.changes.last_mut()
  941            && group
  942        {
  943            last.current = Some(new_positions)
  944        } else {
  945            self.changes.push(ChangeLocation {
  946                original: new_positions,
  947                current: None,
  948            });
  949        }
  950    }
  951
  952    pub fn last(&self) -> Option<&[Anchor]> {
  953        self.changes.last().map(|change| change.locations())
  954    }
  955
  956    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  957        self.changes.last().map(|change| change.original.as_slice())
  958    }
  959
  960    pub fn invert_last_group(&mut self) {
  961        if let Some(last) = self.changes.last_mut()
  962            && let Some(current) = last.current.as_mut()
  963        {
  964            mem::swap(&mut last.original, current);
  965        }
  966    }
  967}
  968
  969#[derive(Clone)]
  970struct InlineBlamePopoverState {
  971    scroll_handle: ScrollHandle,
  972    commit_message: Option<ParsedCommitMessage>,
  973    markdown: Entity<Markdown>,
  974}
  975
  976struct InlineBlamePopover {
  977    position: gpui::Point<Pixels>,
  978    hide_task: Option<Task<()>>,
  979    popover_bounds: Option<Bounds<Pixels>>,
  980    popover_state: InlineBlamePopoverState,
  981    keyboard_grace: bool,
  982}
  983
  984enum SelectionDragState {
  985    /// State when no drag related activity is detected.
  986    None,
  987    /// State when the mouse is down on a selection that is about to be dragged.
  988    ReadyToDrag {
  989        selection: Selection<Anchor>,
  990        click_position: gpui::Point<Pixels>,
  991        mouse_down_time: Instant,
  992    },
  993    /// State when the mouse is dragging the selection in the editor.
  994    Dragging {
  995        selection: Selection<Anchor>,
  996        drop_cursor: Selection<Anchor>,
  997        hide_drop_cursor: bool,
  998    },
  999}
 1000
 1001enum ColumnarSelectionState {
 1002    FromMouse {
 1003        selection_tail: Anchor,
 1004        display_point: Option<DisplayPoint>,
 1005    },
 1006    FromSelection {
 1007        selection_tail: Anchor,
 1008    },
 1009}
 1010
 1011/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1012/// a breakpoint on them.
 1013#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1014struct PhantomBreakpointIndicator {
 1015    display_row: DisplayRow,
 1016    /// There's a small debounce between hovering over the line and showing the indicator.
 1017    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1018    is_active: bool,
 1019    collides_with_existing_breakpoint: bool,
 1020}
 1021
 1022/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1023///
 1024/// See the [module level documentation](self) for more information.
 1025pub struct Editor {
 1026    focus_handle: FocusHandle,
 1027    last_focused_descendant: Option<WeakFocusHandle>,
 1028    /// The text buffer being edited
 1029    buffer: Entity<MultiBuffer>,
 1030    /// Map of how text in the buffer should be displayed.
 1031    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1032    pub display_map: Entity<DisplayMap>,
 1033    placeholder_display_map: Option<Entity<DisplayMap>>,
 1034    pub selections: SelectionsCollection,
 1035    pub scroll_manager: ScrollManager,
 1036    /// When inline assist editors are linked, they all render cursors because
 1037    /// typing enters text into each of them, even the ones that aren't focused.
 1038    pub(crate) show_cursor_when_unfocused: bool,
 1039    columnar_selection_state: Option<ColumnarSelectionState>,
 1040    add_selections_state: Option<AddSelectionsState>,
 1041    select_next_state: Option<SelectNextState>,
 1042    select_prev_state: Option<SelectNextState>,
 1043    selection_history: SelectionHistory,
 1044    defer_selection_effects: bool,
 1045    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1046    autoclose_regions: Vec<AutocloseRegion>,
 1047    snippet_stack: InvalidationStack<SnippetState>,
 1048    select_syntax_node_history: SelectSyntaxNodeHistory,
 1049    ime_transaction: Option<TransactionId>,
 1050    pub diagnostics_max_severity: DiagnosticSeverity,
 1051    active_diagnostics: ActiveDiagnostic,
 1052    show_inline_diagnostics: bool,
 1053    inline_diagnostics_update: Task<()>,
 1054    inline_diagnostics_enabled: bool,
 1055    diagnostics_enabled: bool,
 1056    word_completions_enabled: bool,
 1057    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1058    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1059    hard_wrap: Option<usize>,
 1060    project: Option<Entity<Project>>,
 1061    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1062    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1063    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1064    blink_manager: Entity<BlinkManager>,
 1065    show_cursor_names: bool,
 1066    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1067    pub show_local_selections: bool,
 1068    mode: EditorMode,
 1069    show_breadcrumbs: bool,
 1070    show_gutter: bool,
 1071    show_scrollbars: ScrollbarAxes,
 1072    minimap_visibility: MinimapVisibility,
 1073    offset_content: bool,
 1074    disable_expand_excerpt_buttons: bool,
 1075    show_line_numbers: Option<bool>,
 1076    use_relative_line_numbers: Option<bool>,
 1077    show_git_diff_gutter: Option<bool>,
 1078    show_code_actions: Option<bool>,
 1079    show_runnables: Option<bool>,
 1080    show_breakpoints: Option<bool>,
 1081    show_wrap_guides: Option<bool>,
 1082    show_indent_guides: Option<bool>,
 1083    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1084    highlight_order: usize,
 1085    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1086    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1087    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1088    scrollbar_marker_state: ScrollbarMarkerState,
 1089    active_indent_guides_state: ActiveIndentGuidesState,
 1090    nav_history: Option<ItemNavHistory>,
 1091    context_menu: RefCell<Option<CodeContextMenu>>,
 1092    context_menu_options: Option<ContextMenuOptions>,
 1093    mouse_context_menu: Option<MouseContextMenu>,
 1094    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1095    inline_blame_popover: Option<InlineBlamePopover>,
 1096    inline_blame_popover_show_task: Option<Task<()>>,
 1097    signature_help_state: SignatureHelpState,
 1098    auto_signature_help: Option<bool>,
 1099    find_all_references_task_sources: Vec<Anchor>,
 1100    next_completion_id: CompletionId,
 1101    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1102    code_actions_task: Option<Task<Result<()>>>,
 1103    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1104    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1105    document_highlights_task: Option<Task<()>>,
 1106    linked_editing_range_task: Option<Task<Option<()>>>,
 1107    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1108    pending_rename: Option<RenameState>,
 1109    searchable: bool,
 1110    cursor_shape: CursorShape,
 1111    /// Whether the cursor is offset one character to the left when something is
 1112    /// selected (needed for vim visual mode)
 1113    cursor_offset_on_selection: bool,
 1114    current_line_highlight: Option<CurrentLineHighlight>,
 1115    pub collapse_matches: bool,
 1116    autoindent_mode: Option<AutoindentMode>,
 1117    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1118    input_enabled: bool,
 1119    use_modal_editing: bool,
 1120    read_only: bool,
 1121    leader_id: Option<CollaboratorId>,
 1122    remote_id: Option<ViewId>,
 1123    pub hover_state: HoverState,
 1124    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1125    prev_pressure_stage: Option<PressureStage>,
 1126    gutter_hovered: bool,
 1127    hovered_link_state: Option<HoveredLinkState>,
 1128    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1129    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1130    active_edit_prediction: Option<EditPredictionState>,
 1131    /// Used to prevent flickering as the user types while the menu is open
 1132    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1133    edit_prediction_settings: EditPredictionSettings,
 1134    edit_predictions_hidden_for_vim_mode: bool,
 1135    show_edit_predictions_override: Option<bool>,
 1136    show_completions_on_input_override: Option<bool>,
 1137    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1138    edit_prediction_preview: EditPredictionPreview,
 1139    edit_prediction_indent_conflict: bool,
 1140    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1141    next_inlay_id: usize,
 1142    next_color_inlay_id: usize,
 1143    _subscriptions: Vec<Subscription>,
 1144    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1145    gutter_dimensions: GutterDimensions,
 1146    style: Option<EditorStyle>,
 1147    text_style_refinement: Option<TextStyleRefinement>,
 1148    next_editor_action_id: EditorActionId,
 1149    editor_actions: Rc<
 1150        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1151    >,
 1152    use_autoclose: bool,
 1153    use_auto_surround: bool,
 1154    auto_replace_emoji_shortcode: bool,
 1155    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1156    show_git_blame_gutter: bool,
 1157    show_git_blame_inline: bool,
 1158    show_git_blame_inline_delay_task: Option<Task<()>>,
 1159    git_blame_inline_enabled: bool,
 1160    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1161    buffer_serialization: Option<BufferSerialization>,
 1162    show_selection_menu: Option<bool>,
 1163    blame: Option<Entity<GitBlame>>,
 1164    blame_subscription: Option<Subscription>,
 1165    custom_context_menu: Option<
 1166        Box<
 1167            dyn 'static
 1168                + Fn(
 1169                    &mut Self,
 1170                    DisplayPoint,
 1171                    &mut Window,
 1172                    &mut Context<Self>,
 1173                ) -> Option<Entity<ui::ContextMenu>>,
 1174        >,
 1175    >,
 1176    last_bounds: Option<Bounds<Pixels>>,
 1177    last_position_map: Option<Rc<PositionMap>>,
 1178    expect_bounds_change: Option<Bounds<Pixels>>,
 1179    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1180    tasks_update_task: Option<Task<()>>,
 1181    breakpoint_store: Option<Entity<BreakpointStore>>,
 1182    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1183    hovered_diff_hunk_row: Option<DisplayRow>,
 1184    pull_diagnostics_task: Task<()>,
 1185    pull_diagnostics_background_task: Task<()>,
 1186    in_project_search: bool,
 1187    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1188    breadcrumb_header: Option<String>,
 1189    focused_block: Option<FocusedBlock>,
 1190    next_scroll_position: NextScrollCursorCenterTopBottom,
 1191    addons: HashMap<TypeId, Box<dyn Addon>>,
 1192    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1193    load_diff_task: Option<Shared<Task<()>>>,
 1194    /// Whether we are temporarily displaying a diff other than git's
 1195    temporary_diff_override: bool,
 1196    selection_mark_mode: bool,
 1197    toggle_fold_multiple_buffers: Task<()>,
 1198    _scroll_cursor_center_top_bottom_task: Task<()>,
 1199    serialize_selections: Task<()>,
 1200    serialize_folds: Task<()>,
 1201    mouse_cursor_hidden: bool,
 1202    minimap: Option<Entity<Self>>,
 1203    hide_mouse_mode: HideMouseMode,
 1204    pub change_list: ChangeList,
 1205    inline_value_cache: InlineValueCache,
 1206
 1207    selection_drag_state: SelectionDragState,
 1208    colors: Option<LspColorData>,
 1209    post_scroll_update: Task<()>,
 1210    refresh_colors_task: Task<()>,
 1211    inlay_hints: Option<LspInlayHintData>,
 1212    folding_newlines: Task<()>,
 1213    select_next_is_case_sensitive: Option<bool>,
 1214    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1215    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1216    accent_data: Option<AccentData>,
 1217    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1218    use_base_text_line_numbers: bool,
 1219}
 1220
 1221#[derive(Debug, PartialEq)]
 1222struct AccentData {
 1223    colors: AccentColors,
 1224    overrides: Vec<SharedString>,
 1225}
 1226
 1227fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1228    if debounce_ms > 0 {
 1229        Some(Duration::from_millis(debounce_ms))
 1230    } else {
 1231        None
 1232    }
 1233}
 1234
 1235#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1236enum NextScrollCursorCenterTopBottom {
 1237    #[default]
 1238    Center,
 1239    Top,
 1240    Bottom,
 1241}
 1242
 1243impl NextScrollCursorCenterTopBottom {
 1244    fn next(&self) -> Self {
 1245        match self {
 1246            Self::Center => Self::Top,
 1247            Self::Top => Self::Bottom,
 1248            Self::Bottom => Self::Center,
 1249        }
 1250    }
 1251}
 1252
 1253#[derive(Clone)]
 1254pub struct EditorSnapshot {
 1255    pub mode: EditorMode,
 1256    show_gutter: bool,
 1257    offset_content: bool,
 1258    show_line_numbers: Option<bool>,
 1259    show_git_diff_gutter: Option<bool>,
 1260    show_code_actions: Option<bool>,
 1261    show_runnables: Option<bool>,
 1262    show_breakpoints: Option<bool>,
 1263    git_blame_gutter_max_author_length: Option<usize>,
 1264    pub display_snapshot: DisplaySnapshot,
 1265    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1266    is_focused: bool,
 1267    scroll_anchor: ScrollAnchor,
 1268    ongoing_scroll: OngoingScroll,
 1269    current_line_highlight: CurrentLineHighlight,
 1270    gutter_hovered: bool,
 1271}
 1272
 1273#[derive(Default, Debug, Clone, Copy)]
 1274pub struct GutterDimensions {
 1275    pub left_padding: Pixels,
 1276    pub right_padding: Pixels,
 1277    pub width: Pixels,
 1278    pub margin: Pixels,
 1279    pub git_blame_entries_width: Option<Pixels>,
 1280}
 1281
 1282impl GutterDimensions {
 1283    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1284        Self {
 1285            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1286            ..Default::default()
 1287        }
 1288    }
 1289
 1290    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1291        -cx.text_system().descent(font_id, font_size)
 1292    }
 1293    /// The full width of the space taken up by the gutter.
 1294    pub fn full_width(&self) -> Pixels {
 1295        self.margin + self.width
 1296    }
 1297
 1298    /// The width of the space reserved for the fold indicators,
 1299    /// use alongside 'justify_end' and `gutter_width` to
 1300    /// right align content with the line numbers
 1301    pub fn fold_area_width(&self) -> Pixels {
 1302        self.margin + self.right_padding
 1303    }
 1304}
 1305
 1306struct CharacterDimensions {
 1307    em_width: Pixels,
 1308    em_advance: Pixels,
 1309    line_height: Pixels,
 1310}
 1311
 1312#[derive(Debug)]
 1313pub struct RemoteSelection {
 1314    pub replica_id: ReplicaId,
 1315    pub selection: Selection<Anchor>,
 1316    pub cursor_shape: CursorShape,
 1317    pub collaborator_id: CollaboratorId,
 1318    pub line_mode: bool,
 1319    pub user_name: Option<SharedString>,
 1320    pub color: PlayerColor,
 1321}
 1322
 1323#[derive(Clone, Debug)]
 1324struct SelectionHistoryEntry {
 1325    selections: Arc<[Selection<Anchor>]>,
 1326    select_next_state: Option<SelectNextState>,
 1327    select_prev_state: Option<SelectNextState>,
 1328    add_selections_state: Option<AddSelectionsState>,
 1329}
 1330
 1331#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1332enum SelectionHistoryMode {
 1333    #[default]
 1334    Normal,
 1335    Undoing,
 1336    Redoing,
 1337    Skipping,
 1338}
 1339
 1340#[derive(Clone, PartialEq, Eq, Hash)]
 1341struct HoveredCursor {
 1342    replica_id: ReplicaId,
 1343    selection_id: usize,
 1344}
 1345
 1346#[derive(Debug)]
 1347/// SelectionEffects controls the side-effects of updating the selection.
 1348///
 1349/// The default behaviour does "what you mostly want":
 1350/// - it pushes to the nav history if the cursor moved by >10 lines
 1351/// - it re-triggers completion requests
 1352/// - it scrolls to fit
 1353///
 1354/// You might want to modify these behaviours. For example when doing a "jump"
 1355/// like go to definition, we always want to add to nav history; but when scrolling
 1356/// in vim mode we never do.
 1357///
 1358/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1359/// move.
 1360#[derive(Clone)]
 1361pub struct SelectionEffects {
 1362    nav_history: Option<bool>,
 1363    completions: bool,
 1364    scroll: Option<Autoscroll>,
 1365}
 1366
 1367impl Default for SelectionEffects {
 1368    fn default() -> Self {
 1369        Self {
 1370            nav_history: None,
 1371            completions: true,
 1372            scroll: Some(Autoscroll::fit()),
 1373        }
 1374    }
 1375}
 1376impl SelectionEffects {
 1377    pub fn scroll(scroll: Autoscroll) -> Self {
 1378        Self {
 1379            scroll: Some(scroll),
 1380            ..Default::default()
 1381        }
 1382    }
 1383
 1384    pub fn no_scroll() -> Self {
 1385        Self {
 1386            scroll: None,
 1387            ..Default::default()
 1388        }
 1389    }
 1390
 1391    pub fn completions(self, completions: bool) -> Self {
 1392        Self {
 1393            completions,
 1394            ..self
 1395        }
 1396    }
 1397
 1398    pub fn nav_history(self, nav_history: bool) -> Self {
 1399        Self {
 1400            nav_history: Some(nav_history),
 1401            ..self
 1402        }
 1403    }
 1404}
 1405
 1406struct DeferredSelectionEffectsState {
 1407    changed: bool,
 1408    effects: SelectionEffects,
 1409    old_cursor_position: Anchor,
 1410    history_entry: SelectionHistoryEntry,
 1411}
 1412
 1413#[derive(Default)]
 1414struct SelectionHistory {
 1415    #[allow(clippy::type_complexity)]
 1416    selections_by_transaction:
 1417        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1418    mode: SelectionHistoryMode,
 1419    undo_stack: VecDeque<SelectionHistoryEntry>,
 1420    redo_stack: VecDeque<SelectionHistoryEntry>,
 1421}
 1422
 1423impl SelectionHistory {
 1424    #[track_caller]
 1425    fn insert_transaction(
 1426        &mut self,
 1427        transaction_id: TransactionId,
 1428        selections: Arc<[Selection<Anchor>]>,
 1429    ) {
 1430        if selections.is_empty() {
 1431            log::error!(
 1432                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1433                std::panic::Location::caller()
 1434            );
 1435            return;
 1436        }
 1437        self.selections_by_transaction
 1438            .insert(transaction_id, (selections, None));
 1439    }
 1440
 1441    #[allow(clippy::type_complexity)]
 1442    fn transaction(
 1443        &self,
 1444        transaction_id: TransactionId,
 1445    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1446        self.selections_by_transaction.get(&transaction_id)
 1447    }
 1448
 1449    #[allow(clippy::type_complexity)]
 1450    fn transaction_mut(
 1451        &mut self,
 1452        transaction_id: TransactionId,
 1453    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1454        self.selections_by_transaction.get_mut(&transaction_id)
 1455    }
 1456
 1457    fn push(&mut self, entry: SelectionHistoryEntry) {
 1458        if !entry.selections.is_empty() {
 1459            match self.mode {
 1460                SelectionHistoryMode::Normal => {
 1461                    self.push_undo(entry);
 1462                    self.redo_stack.clear();
 1463                }
 1464                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1465                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1466                SelectionHistoryMode::Skipping => {}
 1467            }
 1468        }
 1469    }
 1470
 1471    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1472        if self
 1473            .undo_stack
 1474            .back()
 1475            .is_none_or(|e| e.selections != entry.selections)
 1476        {
 1477            self.undo_stack.push_back(entry);
 1478            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1479                self.undo_stack.pop_front();
 1480            }
 1481        }
 1482    }
 1483
 1484    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1485        if self
 1486            .redo_stack
 1487            .back()
 1488            .is_none_or(|e| e.selections != entry.selections)
 1489        {
 1490            self.redo_stack.push_back(entry);
 1491            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1492                self.redo_stack.pop_front();
 1493            }
 1494        }
 1495    }
 1496}
 1497
 1498#[derive(Clone, Copy)]
 1499pub struct RowHighlightOptions {
 1500    pub autoscroll: bool,
 1501    pub include_gutter: bool,
 1502}
 1503
 1504impl Default for RowHighlightOptions {
 1505    fn default() -> Self {
 1506        Self {
 1507            autoscroll: Default::default(),
 1508            include_gutter: true,
 1509        }
 1510    }
 1511}
 1512
 1513struct RowHighlight {
 1514    index: usize,
 1515    range: Range<Anchor>,
 1516    color: Hsla,
 1517    options: RowHighlightOptions,
 1518    type_id: TypeId,
 1519}
 1520
 1521#[derive(Clone, Debug)]
 1522struct AddSelectionsState {
 1523    groups: Vec<AddSelectionsGroup>,
 1524}
 1525
 1526#[derive(Clone, Debug)]
 1527struct AddSelectionsGroup {
 1528    above: bool,
 1529    stack: Vec<usize>,
 1530}
 1531
 1532#[derive(Clone)]
 1533struct SelectNextState {
 1534    query: AhoCorasick,
 1535    wordwise: bool,
 1536    done: bool,
 1537}
 1538
 1539impl std::fmt::Debug for SelectNextState {
 1540    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1541        f.debug_struct(std::any::type_name::<Self>())
 1542            .field("wordwise", &self.wordwise)
 1543            .field("done", &self.done)
 1544            .finish()
 1545    }
 1546}
 1547
 1548#[derive(Debug)]
 1549struct AutocloseRegion {
 1550    selection_id: usize,
 1551    range: Range<Anchor>,
 1552    pair: BracketPair,
 1553}
 1554
 1555#[derive(Debug)]
 1556struct SnippetState {
 1557    ranges: Vec<Vec<Range<Anchor>>>,
 1558    active_index: usize,
 1559    choices: Vec<Option<Vec<String>>>,
 1560}
 1561
 1562#[doc(hidden)]
 1563pub struct RenameState {
 1564    pub range: Range<Anchor>,
 1565    pub old_name: Arc<str>,
 1566    pub editor: Entity<Editor>,
 1567    block_id: CustomBlockId,
 1568}
 1569
 1570struct InvalidationStack<T>(Vec<T>);
 1571
 1572struct RegisteredEditPredictionDelegate {
 1573    provider: Arc<dyn EditPredictionDelegateHandle>,
 1574    _subscription: Subscription,
 1575}
 1576
 1577#[derive(Debug, PartialEq, Eq)]
 1578pub struct ActiveDiagnosticGroup {
 1579    pub active_range: Range<Anchor>,
 1580    pub active_message: String,
 1581    pub group_id: usize,
 1582    pub blocks: HashSet<CustomBlockId>,
 1583}
 1584
 1585#[derive(Debug, PartialEq, Eq)]
 1586
 1587pub(crate) enum ActiveDiagnostic {
 1588    None,
 1589    All,
 1590    Group(ActiveDiagnosticGroup),
 1591}
 1592
 1593#[derive(Serialize, Deserialize, Clone, Debug)]
 1594pub struct ClipboardSelection {
 1595    /// The number of bytes in this selection.
 1596    pub len: usize,
 1597    /// Whether this was a full-line selection.
 1598    pub is_entire_line: bool,
 1599    /// The indentation of the first line when this content was originally copied.
 1600    pub first_line_indent: u32,
 1601    #[serde(default)]
 1602    pub file_path: Option<PathBuf>,
 1603    #[serde(default)]
 1604    pub line_range: Option<RangeInclusive<u32>>,
 1605}
 1606
 1607impl ClipboardSelection {
 1608    pub fn for_buffer(
 1609        len: usize,
 1610        is_entire_line: bool,
 1611        range: Range<Point>,
 1612        buffer: &MultiBufferSnapshot,
 1613        project: Option<&Entity<Project>>,
 1614        cx: &App,
 1615    ) -> Self {
 1616        let first_line_indent = buffer
 1617            .indent_size_for_line(MultiBufferRow(range.start.row))
 1618            .len;
 1619
 1620        let file_path = util::maybe!({
 1621            let project = project?.read(cx);
 1622            let file = buffer.file_at(range.start)?;
 1623            let project_path = ProjectPath {
 1624                worktree_id: file.worktree_id(cx),
 1625                path: file.path().clone(),
 1626            };
 1627            project.absolute_path(&project_path, cx)
 1628        });
 1629
 1630        let line_range = file_path.as_ref().map(|_| range.start.row..=range.end.row);
 1631
 1632        Self {
 1633            len,
 1634            is_entire_line,
 1635            first_line_indent,
 1636            file_path,
 1637            line_range,
 1638        }
 1639    }
 1640}
 1641
 1642// selections, scroll behavior, was newest selection reversed
 1643type SelectSyntaxNodeHistoryState = (
 1644    Box<[Selection<MultiBufferOffset>]>,
 1645    SelectSyntaxNodeScrollBehavior,
 1646    bool,
 1647);
 1648
 1649#[derive(Default)]
 1650struct SelectSyntaxNodeHistory {
 1651    stack: Vec<SelectSyntaxNodeHistoryState>,
 1652    // disable temporarily to allow changing selections without losing the stack
 1653    pub disable_clearing: bool,
 1654}
 1655
 1656impl SelectSyntaxNodeHistory {
 1657    pub fn try_clear(&mut self) {
 1658        if !self.disable_clearing {
 1659            self.stack.clear();
 1660        }
 1661    }
 1662
 1663    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1664        self.stack.push(selection);
 1665    }
 1666
 1667    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1668        self.stack.pop()
 1669    }
 1670}
 1671
 1672enum SelectSyntaxNodeScrollBehavior {
 1673    CursorTop,
 1674    FitSelection,
 1675    CursorBottom,
 1676}
 1677
 1678#[derive(Debug)]
 1679pub(crate) struct NavigationData {
 1680    cursor_anchor: Anchor,
 1681    cursor_position: Point,
 1682    scroll_anchor: ScrollAnchor,
 1683    scroll_top_row: u32,
 1684}
 1685
 1686#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1687pub enum GotoDefinitionKind {
 1688    Symbol,
 1689    Declaration,
 1690    Type,
 1691    Implementation,
 1692}
 1693
 1694pub enum FormatTarget {
 1695    Buffers(HashSet<Entity<Buffer>>),
 1696    Ranges(Vec<Range<MultiBufferPoint>>),
 1697}
 1698
 1699pub(crate) struct FocusedBlock {
 1700    id: BlockId,
 1701    focus_handle: WeakFocusHandle,
 1702}
 1703
 1704#[derive(Clone, Debug)]
 1705enum JumpData {
 1706    MultiBufferRow {
 1707        row: MultiBufferRow,
 1708        line_offset_from_top: u32,
 1709    },
 1710    MultiBufferPoint {
 1711        excerpt_id: ExcerptId,
 1712        position: Point,
 1713        anchor: text::Anchor,
 1714        line_offset_from_top: u32,
 1715    },
 1716}
 1717
 1718pub enum MultibufferSelectionMode {
 1719    First,
 1720    All,
 1721}
 1722
 1723#[derive(Clone, Copy, Debug, Default)]
 1724pub struct RewrapOptions {
 1725    pub override_language_settings: bool,
 1726    pub preserve_existing_whitespace: bool,
 1727}
 1728
 1729impl Editor {
 1730    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1731        let buffer = cx.new(|cx| Buffer::local("", cx));
 1732        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1733        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1734    }
 1735
 1736    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1737        let buffer = cx.new(|cx| Buffer::local("", cx));
 1738        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1739        Self::new(EditorMode::full(), buffer, None, window, cx)
 1740    }
 1741
 1742    pub fn auto_height(
 1743        min_lines: usize,
 1744        max_lines: usize,
 1745        window: &mut Window,
 1746        cx: &mut Context<Self>,
 1747    ) -> Self {
 1748        let buffer = cx.new(|cx| Buffer::local("", cx));
 1749        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1750        Self::new(
 1751            EditorMode::AutoHeight {
 1752                min_lines,
 1753                max_lines: Some(max_lines),
 1754            },
 1755            buffer,
 1756            None,
 1757            window,
 1758            cx,
 1759        )
 1760    }
 1761
 1762    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1763    /// The editor grows as tall as needed to fit its content.
 1764    pub fn auto_height_unbounded(
 1765        min_lines: usize,
 1766        window: &mut Window,
 1767        cx: &mut Context<Self>,
 1768    ) -> Self {
 1769        let buffer = cx.new(|cx| Buffer::local("", cx));
 1770        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1771        Self::new(
 1772            EditorMode::AutoHeight {
 1773                min_lines,
 1774                max_lines: None,
 1775            },
 1776            buffer,
 1777            None,
 1778            window,
 1779            cx,
 1780        )
 1781    }
 1782
 1783    pub fn for_buffer(
 1784        buffer: Entity<Buffer>,
 1785        project: Option<Entity<Project>>,
 1786        window: &mut Window,
 1787        cx: &mut Context<Self>,
 1788    ) -> Self {
 1789        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1790        Self::new(EditorMode::full(), buffer, project, window, cx)
 1791    }
 1792
 1793    pub fn for_multibuffer(
 1794        buffer: Entity<MultiBuffer>,
 1795        project: Option<Entity<Project>>,
 1796        window: &mut Window,
 1797        cx: &mut Context<Self>,
 1798    ) -> Self {
 1799        Self::new(EditorMode::full(), buffer, project, window, cx)
 1800    }
 1801
 1802    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1803        let mut clone = Self::new(
 1804            self.mode.clone(),
 1805            self.buffer.clone(),
 1806            self.project.clone(),
 1807            window,
 1808            cx,
 1809        );
 1810        self.display_map.update(cx, |display_map, cx| {
 1811            let snapshot = display_map.snapshot(cx);
 1812            clone.display_map.update(cx, |display_map, cx| {
 1813                display_map.set_state(&snapshot, cx);
 1814            });
 1815        });
 1816        clone.folds_did_change(cx);
 1817        clone.selections.clone_state(&self.selections);
 1818        clone.scroll_manager.clone_state(&self.scroll_manager);
 1819        clone.searchable = self.searchable;
 1820        clone.read_only = self.read_only;
 1821        clone
 1822    }
 1823
 1824    pub fn new(
 1825        mode: EditorMode,
 1826        buffer: Entity<MultiBuffer>,
 1827        project: Option<Entity<Project>>,
 1828        window: &mut Window,
 1829        cx: &mut Context<Self>,
 1830    ) -> Self {
 1831        Editor::new_internal(mode, buffer, project, None, window, cx)
 1832    }
 1833
 1834    pub fn sticky_headers(
 1835        &self,
 1836        style: &EditorStyle,
 1837        cx: &App,
 1838    ) -> Option<Vec<OutlineItem<Anchor>>> {
 1839        let multi_buffer = self.buffer().read(cx);
 1840        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1841        let multi_buffer_visible_start = self
 1842            .scroll_manager
 1843            .anchor()
 1844            .anchor
 1845            .to_point(&multi_buffer_snapshot);
 1846        let max_row = multi_buffer_snapshot.max_point().row;
 1847
 1848        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1849        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1850
 1851        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1852            let outline_items = buffer
 1853                .outline_items_containing(
 1854                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1855                    true,
 1856                    Some(style.syntax.as_ref()),
 1857                )
 1858                .into_iter()
 1859                .map(|outline_item| OutlineItem {
 1860                    depth: outline_item.depth,
 1861                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1862                    source_range_for_text: Anchor::range_in_buffer(
 1863                        *excerpt_id,
 1864                        outline_item.source_range_for_text,
 1865                    ),
 1866                    text: outline_item.text,
 1867                    highlight_ranges: outline_item.highlight_ranges,
 1868                    name_ranges: outline_item.name_ranges,
 1869                    body_range: outline_item
 1870                        .body_range
 1871                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1872                    annotation_range: outline_item
 1873                        .annotation_range
 1874                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1875                });
 1876            return Some(outline_items.collect());
 1877        }
 1878
 1879        None
 1880    }
 1881
 1882    fn new_internal(
 1883        mode: EditorMode,
 1884        multi_buffer: Entity<MultiBuffer>,
 1885        project: Option<Entity<Project>>,
 1886        display_map: Option<Entity<DisplayMap>>,
 1887        window: &mut Window,
 1888        cx: &mut Context<Self>,
 1889    ) -> Self {
 1890        debug_assert!(
 1891            display_map.is_none() || mode.is_minimap(),
 1892            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1893        );
 1894
 1895        let full_mode = mode.is_full();
 1896        let is_minimap = mode.is_minimap();
 1897        let diagnostics_max_severity = if full_mode {
 1898            EditorSettings::get_global(cx)
 1899                .diagnostics_max_severity
 1900                .unwrap_or(DiagnosticSeverity::Hint)
 1901        } else {
 1902            DiagnosticSeverity::Off
 1903        };
 1904        let style = window.text_style();
 1905        let font_size = style.font_size.to_pixels(window.rem_size());
 1906        let editor = cx.entity().downgrade();
 1907        let fold_placeholder = FoldPlaceholder {
 1908            constrain_width: false,
 1909            render: Arc::new(move |fold_id, fold_range, cx| {
 1910                let editor = editor.clone();
 1911                div()
 1912                    .id(fold_id)
 1913                    .bg(cx.theme().colors().ghost_element_background)
 1914                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1915                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1916                    .rounded_xs()
 1917                    .size_full()
 1918                    .cursor_pointer()
 1919                    .child("")
 1920                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1921                    .on_click(move |_, _window, cx| {
 1922                        editor
 1923                            .update(cx, |editor, cx| {
 1924                                editor.unfold_ranges(
 1925                                    &[fold_range.start..fold_range.end],
 1926                                    true,
 1927                                    false,
 1928                                    cx,
 1929                                );
 1930                                cx.stop_propagation();
 1931                            })
 1932                            .ok();
 1933                    })
 1934                    .into_any()
 1935            }),
 1936            merge_adjacent: true,
 1937            ..FoldPlaceholder::default()
 1938        };
 1939        let display_map = display_map.unwrap_or_else(|| {
 1940            cx.new(|cx| {
 1941                DisplayMap::new(
 1942                    multi_buffer.clone(),
 1943                    style.font(),
 1944                    font_size,
 1945                    None,
 1946                    FILE_HEADER_HEIGHT,
 1947                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1948                    fold_placeholder,
 1949                    diagnostics_max_severity,
 1950                    cx,
 1951                )
 1952            })
 1953        });
 1954
 1955        let selections = SelectionsCollection::new();
 1956
 1957        let blink_manager = cx.new(|cx| {
 1958            let mut blink_manager = BlinkManager::new(
 1959                CURSOR_BLINK_INTERVAL,
 1960                |cx| EditorSettings::get_global(cx).cursor_blink,
 1961                cx,
 1962            );
 1963            if is_minimap {
 1964                blink_manager.disable(cx);
 1965            }
 1966            blink_manager
 1967        });
 1968
 1969        let soft_wrap_mode_override =
 1970            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1971
 1972        let mut project_subscriptions = Vec::new();
 1973        if full_mode && let Some(project) = project.as_ref() {
 1974            project_subscriptions.push(cx.subscribe_in(
 1975                project,
 1976                window,
 1977                |editor, _, event, window, cx| match event {
 1978                    project::Event::RefreshCodeLens => {
 1979                        // we always query lens with actions, without storing them, always refreshing them
 1980                    }
 1981                    project::Event::RefreshInlayHints {
 1982                        server_id,
 1983                        request_id,
 1984                    } => {
 1985                        editor.refresh_inlay_hints(
 1986                            InlayHintRefreshReason::RefreshRequested {
 1987                                server_id: *server_id,
 1988                                request_id: *request_id,
 1989                            },
 1990                            cx,
 1991                        );
 1992                    }
 1993                    project::Event::LanguageServerRemoved(..) => {
 1994                        if editor.tasks_update_task.is_none() {
 1995                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1996                        }
 1997                        editor.registered_buffers.clear();
 1998                        editor.register_visible_buffers(cx);
 1999                    }
 2000                    project::Event::LanguageServerAdded(..) => {
 2001                        if editor.tasks_update_task.is_none() {
 2002                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2003                        }
 2004                    }
 2005                    project::Event::SnippetEdit(id, snippet_edits) => {
 2006                        // todo(lw): Non singletons
 2007                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2008                            let snapshot = buffer.read(cx).snapshot();
 2009                            let focus_handle = editor.focus_handle(cx);
 2010                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2011                                for (range, snippet) in snippet_edits {
 2012                                    let buffer_range =
 2013                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2014                                    editor
 2015                                        .insert_snippet(
 2016                                            &[MultiBufferOffset(buffer_range.start)
 2017                                                ..MultiBufferOffset(buffer_range.end)],
 2018                                            snippet.clone(),
 2019                                            window,
 2020                                            cx,
 2021                                        )
 2022                                        .ok();
 2023                                }
 2024                            }
 2025                        }
 2026                    }
 2027                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2028                        let buffer_id = *buffer_id;
 2029                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2030                            editor.register_buffer(buffer_id, cx);
 2031                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2032                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2033                            refresh_linked_ranges(editor, window, cx);
 2034                            editor.refresh_code_actions(window, cx);
 2035                            editor.refresh_document_highlights(cx);
 2036                        }
 2037                    }
 2038
 2039                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2040                        let Some(workspace) = editor.workspace() else {
 2041                            return;
 2042                        };
 2043                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2044                        else {
 2045                            return;
 2046                        };
 2047
 2048                        if active_editor.entity_id() == cx.entity_id() {
 2049                            let entity_id = cx.entity_id();
 2050                            workspace.update(cx, |this, cx| {
 2051                                this.panes_mut()
 2052                                    .iter_mut()
 2053                                    .filter(|pane| pane.entity_id() != entity_id)
 2054                                    .for_each(|p| {
 2055                                        p.update(cx, |pane, _| {
 2056                                            pane.nav_history_mut().rename_item(
 2057                                                entity_id,
 2058                                                project_path.clone(),
 2059                                                abs_path.clone().into(),
 2060                                            );
 2061                                        })
 2062                                    });
 2063                            });
 2064                            let edited_buffers_already_open = {
 2065                                let other_editors: Vec<Entity<Editor>> = workspace
 2066                                    .read(cx)
 2067                                    .panes()
 2068                                    .iter()
 2069                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 2070                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 2071                                    .collect();
 2072
 2073                                transaction.0.keys().all(|buffer| {
 2074                                    other_editors.iter().any(|editor| {
 2075                                        let multi_buffer = editor.read(cx).buffer();
 2076                                        multi_buffer.read(cx).is_singleton()
 2077                                            && multi_buffer.read(cx).as_singleton().map_or(
 2078                                                false,
 2079                                                |singleton| {
 2080                                                    singleton.entity_id() == buffer.entity_id()
 2081                                                },
 2082                                            )
 2083                                    })
 2084                                })
 2085                            };
 2086                            if !edited_buffers_already_open {
 2087                                let workspace = workspace.downgrade();
 2088                                let transaction = transaction.clone();
 2089                                cx.defer_in(window, move |_, window, cx| {
 2090                                    cx.spawn_in(window, async move |editor, cx| {
 2091                                        Self::open_project_transaction(
 2092                                            &editor,
 2093                                            workspace,
 2094                                            transaction,
 2095                                            "Rename".to_string(),
 2096                                            cx,
 2097                                        )
 2098                                        .await
 2099                                        .ok()
 2100                                    })
 2101                                    .detach();
 2102                                });
 2103                            }
 2104                        }
 2105                    }
 2106
 2107                    _ => {}
 2108                },
 2109            ));
 2110            if let Some(task_inventory) = project
 2111                .read(cx)
 2112                .task_store()
 2113                .read(cx)
 2114                .task_inventory()
 2115                .cloned()
 2116            {
 2117                project_subscriptions.push(cx.observe_in(
 2118                    &task_inventory,
 2119                    window,
 2120                    |editor, _, window, cx| {
 2121                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2122                    },
 2123                ));
 2124            };
 2125
 2126            project_subscriptions.push(cx.subscribe_in(
 2127                &project.read(cx).breakpoint_store(),
 2128                window,
 2129                |editor, _, event, window, cx| match event {
 2130                    BreakpointStoreEvent::ClearDebugLines => {
 2131                        editor.clear_row_highlights::<ActiveDebugLine>();
 2132                        editor.refresh_inline_values(cx);
 2133                    }
 2134                    BreakpointStoreEvent::SetDebugLine => {
 2135                        if editor.go_to_active_debug_line(window, cx) {
 2136                            cx.stop_propagation();
 2137                        }
 2138
 2139                        editor.refresh_inline_values(cx);
 2140                    }
 2141                    _ => {}
 2142                },
 2143            ));
 2144            let git_store = project.read(cx).git_store().clone();
 2145            let project = project.clone();
 2146            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2147                if let GitStoreEvent::RepositoryAdded = event {
 2148                    this.load_diff_task = Some(
 2149                        update_uncommitted_diff_for_buffer(
 2150                            cx.entity(),
 2151                            &project,
 2152                            this.buffer.read(cx).all_buffers(),
 2153                            this.buffer.clone(),
 2154                            cx,
 2155                        )
 2156                        .shared(),
 2157                    );
 2158                }
 2159            }));
 2160        }
 2161
 2162        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2163
 2164        let inlay_hint_settings =
 2165            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2166        let focus_handle = cx.focus_handle();
 2167        if !is_minimap {
 2168            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2169                .detach();
 2170            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2171                .detach();
 2172            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2173                .detach();
 2174            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2175                .detach();
 2176            cx.observe_pending_input(window, Self::observe_pending_input)
 2177                .detach();
 2178        }
 2179
 2180        let show_indent_guides =
 2181            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2182                Some(false)
 2183            } else {
 2184                None
 2185            };
 2186
 2187        let breakpoint_store = match (&mode, project.as_ref()) {
 2188            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2189            _ => None,
 2190        };
 2191
 2192        let mut code_action_providers = Vec::new();
 2193        let mut load_uncommitted_diff = None;
 2194        if let Some(project) = project.clone() {
 2195            load_uncommitted_diff = Some(
 2196                update_uncommitted_diff_for_buffer(
 2197                    cx.entity(),
 2198                    &project,
 2199                    multi_buffer.read(cx).all_buffers(),
 2200                    multi_buffer.clone(),
 2201                    cx,
 2202                )
 2203                .shared(),
 2204            );
 2205            code_action_providers.push(Rc::new(project) as Rc<_>);
 2206        }
 2207
 2208        let mut editor = Self {
 2209            focus_handle,
 2210            show_cursor_when_unfocused: false,
 2211            last_focused_descendant: None,
 2212            buffer: multi_buffer.clone(),
 2213            display_map: display_map.clone(),
 2214            placeholder_display_map: None,
 2215            selections,
 2216            scroll_manager: ScrollManager::new(cx),
 2217            columnar_selection_state: None,
 2218            add_selections_state: None,
 2219            select_next_state: None,
 2220            select_prev_state: None,
 2221            selection_history: SelectionHistory::default(),
 2222            defer_selection_effects: false,
 2223            deferred_selection_effects_state: None,
 2224            autoclose_regions: Vec::new(),
 2225            snippet_stack: InvalidationStack::default(),
 2226            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2227            ime_transaction: None,
 2228            active_diagnostics: ActiveDiagnostic::None,
 2229            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2230            inline_diagnostics_update: Task::ready(()),
 2231            inline_diagnostics: Vec::new(),
 2232            soft_wrap_mode_override,
 2233            diagnostics_max_severity,
 2234            hard_wrap: None,
 2235            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2236            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2237            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2238            project,
 2239            blink_manager: blink_manager.clone(),
 2240            show_local_selections: true,
 2241            show_scrollbars: ScrollbarAxes {
 2242                horizontal: full_mode,
 2243                vertical: full_mode,
 2244            },
 2245            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2246            offset_content: !matches!(mode, EditorMode::SingleLine),
 2247            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2248            show_gutter: full_mode,
 2249            show_line_numbers: (!full_mode).then_some(false),
 2250            use_relative_line_numbers: None,
 2251            disable_expand_excerpt_buttons: !full_mode,
 2252            show_git_diff_gutter: None,
 2253            show_code_actions: None,
 2254            show_runnables: None,
 2255            show_breakpoints: None,
 2256            show_wrap_guides: None,
 2257            show_indent_guides,
 2258            buffers_with_disabled_indent_guides: HashSet::default(),
 2259            highlight_order: 0,
 2260            highlighted_rows: HashMap::default(),
 2261            background_highlights: HashMap::default(),
 2262            gutter_highlights: HashMap::default(),
 2263            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2264            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2265            nav_history: None,
 2266            context_menu: RefCell::new(None),
 2267            context_menu_options: None,
 2268            mouse_context_menu: None,
 2269            completion_tasks: Vec::new(),
 2270            inline_blame_popover: None,
 2271            inline_blame_popover_show_task: None,
 2272            signature_help_state: SignatureHelpState::default(),
 2273            auto_signature_help: None,
 2274            find_all_references_task_sources: Vec::new(),
 2275            next_completion_id: 0,
 2276            next_inlay_id: 0,
 2277            code_action_providers,
 2278            available_code_actions: None,
 2279            code_actions_task: None,
 2280            quick_selection_highlight_task: None,
 2281            debounced_selection_highlight_task: None,
 2282            document_highlights_task: None,
 2283            linked_editing_range_task: None,
 2284            pending_rename: None,
 2285            searchable: !is_minimap,
 2286            cursor_shape: EditorSettings::get_global(cx)
 2287                .cursor_shape
 2288                .unwrap_or_default(),
 2289            cursor_offset_on_selection: false,
 2290            current_line_highlight: None,
 2291            autoindent_mode: Some(AutoindentMode::EachLine),
 2292            collapse_matches: false,
 2293            workspace: None,
 2294            input_enabled: !is_minimap,
 2295            use_modal_editing: full_mode,
 2296            read_only: is_minimap,
 2297            use_autoclose: true,
 2298            use_auto_surround: true,
 2299            auto_replace_emoji_shortcode: false,
 2300            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2301            leader_id: None,
 2302            remote_id: None,
 2303            hover_state: HoverState::default(),
 2304            pending_mouse_down: None,
 2305            prev_pressure_stage: None,
 2306            hovered_link_state: None,
 2307            edit_prediction_provider: None,
 2308            active_edit_prediction: None,
 2309            stale_edit_prediction_in_menu: None,
 2310            edit_prediction_preview: EditPredictionPreview::Inactive {
 2311                released_too_fast: false,
 2312            },
 2313            inline_diagnostics_enabled: full_mode,
 2314            diagnostics_enabled: full_mode,
 2315            word_completions_enabled: full_mode,
 2316            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2317            gutter_hovered: false,
 2318            pixel_position_of_newest_cursor: None,
 2319            last_bounds: None,
 2320            last_position_map: None,
 2321            expect_bounds_change: None,
 2322            gutter_dimensions: GutterDimensions::default(),
 2323            style: None,
 2324            show_cursor_names: false,
 2325            hovered_cursors: HashMap::default(),
 2326            next_editor_action_id: EditorActionId::default(),
 2327            editor_actions: Rc::default(),
 2328            edit_predictions_hidden_for_vim_mode: false,
 2329            show_edit_predictions_override: None,
 2330            show_completions_on_input_override: None,
 2331            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2332            edit_prediction_settings: EditPredictionSettings::Disabled,
 2333            edit_prediction_indent_conflict: false,
 2334            edit_prediction_requires_modifier_in_indent_conflict: true,
 2335            custom_context_menu: None,
 2336            show_git_blame_gutter: false,
 2337            show_git_blame_inline: false,
 2338            show_selection_menu: None,
 2339            show_git_blame_inline_delay_task: None,
 2340            git_blame_inline_enabled: full_mode
 2341                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2342            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2343            buffer_serialization: is_minimap.not().then(|| {
 2344                BufferSerialization::new(
 2345                    ProjectSettings::get_global(cx)
 2346                        .session
 2347                        .restore_unsaved_buffers,
 2348                )
 2349            }),
 2350            blame: None,
 2351            blame_subscription: None,
 2352            tasks: BTreeMap::default(),
 2353
 2354            breakpoint_store,
 2355            gutter_breakpoint_indicator: (None, None),
 2356            hovered_diff_hunk_row: None,
 2357            _subscriptions: (!is_minimap)
 2358                .then(|| {
 2359                    vec![
 2360                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2361                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2362                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2363                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2364                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2365                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2366                        cx.observe_window_activation(window, |editor, window, cx| {
 2367                            let active = window.is_window_active();
 2368                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2369                                if active {
 2370                                    blink_manager.enable(cx);
 2371                                } else {
 2372                                    blink_manager.disable(cx);
 2373                                }
 2374                            });
 2375                            if active {
 2376                                editor.show_mouse_cursor(cx);
 2377                            }
 2378                        }),
 2379                    ]
 2380                })
 2381                .unwrap_or_default(),
 2382            tasks_update_task: None,
 2383            pull_diagnostics_task: Task::ready(()),
 2384            pull_diagnostics_background_task: Task::ready(()),
 2385            colors: None,
 2386            refresh_colors_task: Task::ready(()),
 2387            inlay_hints: None,
 2388            next_color_inlay_id: 0,
 2389            post_scroll_update: Task::ready(()),
 2390            linked_edit_ranges: Default::default(),
 2391            in_project_search: false,
 2392            previous_search_ranges: None,
 2393            breadcrumb_header: None,
 2394            focused_block: None,
 2395            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2396            addons: HashMap::default(),
 2397            registered_buffers: HashMap::default(),
 2398            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2399            selection_mark_mode: false,
 2400            toggle_fold_multiple_buffers: Task::ready(()),
 2401            serialize_selections: Task::ready(()),
 2402            serialize_folds: Task::ready(()),
 2403            text_style_refinement: None,
 2404            load_diff_task: load_uncommitted_diff,
 2405            temporary_diff_override: false,
 2406            mouse_cursor_hidden: false,
 2407            minimap: None,
 2408            hide_mouse_mode: EditorSettings::get_global(cx)
 2409                .hide_mouse
 2410                .unwrap_or_default(),
 2411            change_list: ChangeList::new(),
 2412            mode,
 2413            selection_drag_state: SelectionDragState::None,
 2414            folding_newlines: Task::ready(()),
 2415            lookup_key: None,
 2416            select_next_is_case_sensitive: None,
 2417            applicable_language_settings: HashMap::default(),
 2418            accent_data: None,
 2419            fetched_tree_sitter_chunks: HashMap::default(),
 2420            use_base_text_line_numbers: false,
 2421        };
 2422
 2423        if is_minimap {
 2424            return editor;
 2425        }
 2426
 2427        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2428        editor.accent_data = editor.fetch_accent_data(cx);
 2429
 2430        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2431            editor
 2432                ._subscriptions
 2433                .push(cx.observe(breakpoints, |_, _, cx| {
 2434                    cx.notify();
 2435                }));
 2436        }
 2437        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2438        editor._subscriptions.extend(project_subscriptions);
 2439
 2440        editor._subscriptions.push(cx.subscribe_in(
 2441            &cx.entity(),
 2442            window,
 2443            |editor, _, e: &EditorEvent, window, cx| match e {
 2444                EditorEvent::ScrollPositionChanged { local, .. } => {
 2445                    if *local {
 2446                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2447                        editor.inline_blame_popover.take();
 2448                        let new_anchor = editor.scroll_manager.anchor();
 2449                        let snapshot = editor.snapshot(window, cx);
 2450                        editor.update_restoration_data(cx, move |data| {
 2451                            data.scroll_position = (
 2452                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2453                                new_anchor.offset,
 2454                            );
 2455                        });
 2456
 2457                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2458                            cx.background_executor()
 2459                                .timer(Duration::from_millis(50))
 2460                                .await;
 2461                            editor
 2462                                .update_in(cx, |editor, window, cx| {
 2463                                    editor.register_visible_buffers(cx);
 2464                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2465                                    editor.refresh_inlay_hints(
 2466                                        InlayHintRefreshReason::NewLinesShown,
 2467                                        cx,
 2468                                    );
 2469                                    editor.colorize_brackets(false, cx);
 2470                                })
 2471                                .ok();
 2472                        });
 2473                    }
 2474                }
 2475                EditorEvent::Edited { .. } => {
 2476                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2477                        .map(|vim_mode| vim_mode.0)
 2478                        .unwrap_or(false);
 2479                    if !vim_mode {
 2480                        let display_map = editor.display_snapshot(cx);
 2481                        let selections = editor.selections.all_adjusted_display(&display_map);
 2482                        let pop_state = editor
 2483                            .change_list
 2484                            .last()
 2485                            .map(|previous| {
 2486                                previous.len() == selections.len()
 2487                                    && previous.iter().enumerate().all(|(ix, p)| {
 2488                                        p.to_display_point(&display_map).row()
 2489                                            == selections[ix].head().row()
 2490                                    })
 2491                            })
 2492                            .unwrap_or(false);
 2493                        let new_positions = selections
 2494                            .into_iter()
 2495                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2496                            .collect();
 2497                        editor
 2498                            .change_list
 2499                            .push_to_change_list(pop_state, new_positions);
 2500                    }
 2501                }
 2502                _ => (),
 2503            },
 2504        ));
 2505
 2506        if let Some(dap_store) = editor
 2507            .project
 2508            .as_ref()
 2509            .map(|project| project.read(cx).dap_store())
 2510        {
 2511            let weak_editor = cx.weak_entity();
 2512
 2513            editor
 2514                ._subscriptions
 2515                .push(
 2516                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2517                        let session_entity = cx.entity();
 2518                        weak_editor
 2519                            .update(cx, |editor, cx| {
 2520                                editor._subscriptions.push(
 2521                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2522                                );
 2523                            })
 2524                            .ok();
 2525                    }),
 2526                );
 2527
 2528            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2529                editor
 2530                    ._subscriptions
 2531                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2532            }
 2533        }
 2534
 2535        // skip adding the initial selection to selection history
 2536        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2537        editor.end_selection(window, cx);
 2538        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2539
 2540        editor.scroll_manager.show_scrollbars(window, cx);
 2541        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2542
 2543        if full_mode {
 2544            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2545            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2546
 2547            if editor.git_blame_inline_enabled {
 2548                editor.start_git_blame_inline(false, window, cx);
 2549            }
 2550
 2551            editor.go_to_active_debug_line(window, cx);
 2552
 2553            editor.minimap =
 2554                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2555            editor.colors = Some(LspColorData::new(cx));
 2556            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2557
 2558            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2559                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2560            }
 2561            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2562        }
 2563
 2564        editor
 2565    }
 2566
 2567    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2568        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2569    }
 2570
 2571    pub fn deploy_mouse_context_menu(
 2572        &mut self,
 2573        position: gpui::Point<Pixels>,
 2574        context_menu: Entity<ContextMenu>,
 2575        window: &mut Window,
 2576        cx: &mut Context<Self>,
 2577    ) {
 2578        self.mouse_context_menu = Some(MouseContextMenu::new(
 2579            self,
 2580            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2581            context_menu,
 2582            window,
 2583            cx,
 2584        ));
 2585    }
 2586
 2587    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2588        self.mouse_context_menu
 2589            .as_ref()
 2590            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2591    }
 2592
 2593    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2594        if self
 2595            .selections
 2596            .pending_anchor()
 2597            .is_some_and(|pending_selection| {
 2598                let snapshot = self.buffer().read(cx).snapshot(cx);
 2599                pending_selection.range().includes(range, &snapshot)
 2600            })
 2601        {
 2602            return true;
 2603        }
 2604
 2605        self.selections
 2606            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2607            .into_iter()
 2608            .any(|selection| {
 2609                // This is needed to cover a corner case, if we just check for an existing
 2610                // selection in the fold range, having a cursor at the start of the fold
 2611                // marks it as selected. Non-empty selections don't cause this.
 2612                let length = selection.end - selection.start;
 2613                length > 0
 2614            })
 2615    }
 2616
 2617    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2618        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2619    }
 2620
 2621    fn key_context_internal(
 2622        &self,
 2623        has_active_edit_prediction: bool,
 2624        window: &mut Window,
 2625        cx: &mut App,
 2626    ) -> KeyContext {
 2627        let mut key_context = KeyContext::new_with_defaults();
 2628        key_context.add("Editor");
 2629        let mode = match self.mode {
 2630            EditorMode::SingleLine => "single_line",
 2631            EditorMode::AutoHeight { .. } => "auto_height",
 2632            EditorMode::Minimap { .. } => "minimap",
 2633            EditorMode::Full { .. } => "full",
 2634        };
 2635
 2636        if EditorSettings::jupyter_enabled(cx) {
 2637            key_context.add("jupyter");
 2638        }
 2639
 2640        key_context.set("mode", mode);
 2641        if self.pending_rename.is_some() {
 2642            key_context.add("renaming");
 2643        }
 2644
 2645        if let Some(snippet_stack) = self.snippet_stack.last() {
 2646            key_context.add("in_snippet");
 2647
 2648            if snippet_stack.active_index > 0 {
 2649                key_context.add("has_previous_tabstop");
 2650            }
 2651
 2652            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2653                key_context.add("has_next_tabstop");
 2654            }
 2655        }
 2656
 2657        match self.context_menu.borrow().as_ref() {
 2658            Some(CodeContextMenu::Completions(menu)) => {
 2659                if menu.visible() {
 2660                    key_context.add("menu");
 2661                    key_context.add("showing_completions");
 2662                }
 2663            }
 2664            Some(CodeContextMenu::CodeActions(menu)) => {
 2665                if menu.visible() {
 2666                    key_context.add("menu");
 2667                    key_context.add("showing_code_actions")
 2668                }
 2669            }
 2670            None => {}
 2671        }
 2672
 2673        if self.signature_help_state.has_multiple_signatures() {
 2674            key_context.add("showing_signature_help");
 2675        }
 2676
 2677        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2678        if !self.focus_handle(cx).contains_focused(window, cx)
 2679            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2680        {
 2681            for addon in self.addons.values() {
 2682                addon.extend_key_context(&mut key_context, cx)
 2683            }
 2684        }
 2685
 2686        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2687            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2688                Some(
 2689                    file.full_path(cx)
 2690                        .extension()?
 2691                        .to_string_lossy()
 2692                        .into_owned(),
 2693                )
 2694            }) {
 2695                key_context.set("extension", extension);
 2696            }
 2697        } else {
 2698            key_context.add("multibuffer");
 2699        }
 2700
 2701        if has_active_edit_prediction {
 2702            if self.edit_prediction_in_conflict() {
 2703                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2704            } else {
 2705                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2706                key_context.add("copilot_suggestion");
 2707            }
 2708        }
 2709
 2710        if self.selection_mark_mode {
 2711            key_context.add("selection_mode");
 2712        }
 2713
 2714        let disjoint = self.selections.disjoint_anchors();
 2715        let snapshot = self.snapshot(window, cx);
 2716        let snapshot = snapshot.buffer_snapshot();
 2717        if self.mode == EditorMode::SingleLine
 2718            && let [selection] = disjoint
 2719            && selection.start == selection.end
 2720            && selection.end.to_offset(snapshot) == snapshot.len()
 2721        {
 2722            key_context.add("end_of_input");
 2723        }
 2724
 2725        if self.has_any_expanded_diff_hunks(cx) {
 2726            key_context.add("diffs_expanded");
 2727        }
 2728
 2729        key_context
 2730    }
 2731
 2732    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2733        self.last_bounds.as_ref()
 2734    }
 2735
 2736    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2737        if self.mouse_cursor_hidden {
 2738            self.mouse_cursor_hidden = false;
 2739            cx.notify();
 2740        }
 2741    }
 2742
 2743    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2744        let hide_mouse_cursor = match origin {
 2745            HideMouseCursorOrigin::TypingAction => {
 2746                matches!(
 2747                    self.hide_mouse_mode,
 2748                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2749                )
 2750            }
 2751            HideMouseCursorOrigin::MovementAction => {
 2752                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2753            }
 2754        };
 2755        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2756            self.mouse_cursor_hidden = hide_mouse_cursor;
 2757            cx.notify();
 2758        }
 2759    }
 2760
 2761    pub fn edit_prediction_in_conflict(&self) -> bool {
 2762        if !self.show_edit_predictions_in_menu() {
 2763            return false;
 2764        }
 2765
 2766        let showing_completions = self
 2767            .context_menu
 2768            .borrow()
 2769            .as_ref()
 2770            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2771
 2772        showing_completions
 2773            || self.edit_prediction_requires_modifier()
 2774            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2775            // bindings to insert tab characters.
 2776            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2777    }
 2778
 2779    pub fn accept_edit_prediction_keybind(
 2780        &self,
 2781        accept_partial: bool,
 2782        window: &mut Window,
 2783        cx: &mut App,
 2784    ) -> AcceptEditPredictionBinding {
 2785        let key_context = self.key_context_internal(true, window, cx);
 2786        let in_conflict = self.edit_prediction_in_conflict();
 2787
 2788        let bindings = if accept_partial {
 2789            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2790        } else {
 2791            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2792        };
 2793
 2794        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2795        // just the first one.
 2796        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2797            !in_conflict
 2798                || binding
 2799                    .keystrokes()
 2800                    .first()
 2801                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2802        }))
 2803    }
 2804
 2805    pub fn new_file(
 2806        workspace: &mut Workspace,
 2807        _: &workspace::NewFile,
 2808        window: &mut Window,
 2809        cx: &mut Context<Workspace>,
 2810    ) {
 2811        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2812            "Failed to create buffer",
 2813            window,
 2814            cx,
 2815            |e, _, _| match e.error_code() {
 2816                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2817                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2818                e.error_tag("required").unwrap_or("the latest version")
 2819            )),
 2820                _ => None,
 2821            },
 2822        );
 2823    }
 2824
 2825    pub fn new_in_workspace(
 2826        workspace: &mut Workspace,
 2827        window: &mut Window,
 2828        cx: &mut Context<Workspace>,
 2829    ) -> Task<Result<Entity<Editor>>> {
 2830        let project = workspace.project().clone();
 2831        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2832
 2833        cx.spawn_in(window, async move |workspace, cx| {
 2834            let buffer = create.await?;
 2835            workspace.update_in(cx, |workspace, window, cx| {
 2836                let editor =
 2837                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2838                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2839                editor
 2840            })
 2841        })
 2842    }
 2843
 2844    fn new_file_vertical(
 2845        workspace: &mut Workspace,
 2846        _: &workspace::NewFileSplitVertical,
 2847        window: &mut Window,
 2848        cx: &mut Context<Workspace>,
 2849    ) {
 2850        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2851    }
 2852
 2853    fn new_file_horizontal(
 2854        workspace: &mut Workspace,
 2855        _: &workspace::NewFileSplitHorizontal,
 2856        window: &mut Window,
 2857        cx: &mut Context<Workspace>,
 2858    ) {
 2859        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2860    }
 2861
 2862    fn new_file_split(
 2863        workspace: &mut Workspace,
 2864        action: &workspace::NewFileSplit,
 2865        window: &mut Window,
 2866        cx: &mut Context<Workspace>,
 2867    ) {
 2868        Self::new_file_in_direction(workspace, action.0, window, cx)
 2869    }
 2870
 2871    fn new_file_in_direction(
 2872        workspace: &mut Workspace,
 2873        direction: SplitDirection,
 2874        window: &mut Window,
 2875        cx: &mut Context<Workspace>,
 2876    ) {
 2877        let project = workspace.project().clone();
 2878        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2879
 2880        cx.spawn_in(window, async move |workspace, cx| {
 2881            let buffer = create.await?;
 2882            workspace.update_in(cx, move |workspace, window, cx| {
 2883                workspace.split_item(
 2884                    direction,
 2885                    Box::new(
 2886                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2887                    ),
 2888                    window,
 2889                    cx,
 2890                )
 2891            })?;
 2892            anyhow::Ok(())
 2893        })
 2894        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2895            match e.error_code() {
 2896                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2897                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2898                e.error_tag("required").unwrap_or("the latest version")
 2899            )),
 2900                _ => None,
 2901            }
 2902        });
 2903    }
 2904
 2905    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2906        self.leader_id
 2907    }
 2908
 2909    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2910        &self.buffer
 2911    }
 2912
 2913    pub fn project(&self) -> Option<&Entity<Project>> {
 2914        self.project.as_ref()
 2915    }
 2916
 2917    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2918        self.workspace.as_ref()?.0.upgrade()
 2919    }
 2920
 2921    /// Returns the workspace serialization ID if this editor should be serialized.
 2922    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2923        self.workspace
 2924            .as_ref()
 2925            .filter(|_| self.should_serialize_buffer())
 2926            .and_then(|workspace| workspace.1)
 2927    }
 2928
 2929    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2930        self.buffer().read(cx).title(cx)
 2931    }
 2932
 2933    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2934        let git_blame_gutter_max_author_length = self
 2935            .render_git_blame_gutter(cx)
 2936            .then(|| {
 2937                if let Some(blame) = self.blame.as_ref() {
 2938                    let max_author_length =
 2939                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2940                    Some(max_author_length)
 2941                } else {
 2942                    None
 2943                }
 2944            })
 2945            .flatten();
 2946
 2947        EditorSnapshot {
 2948            mode: self.mode.clone(),
 2949            show_gutter: self.show_gutter,
 2950            offset_content: self.offset_content,
 2951            show_line_numbers: self.show_line_numbers,
 2952            show_git_diff_gutter: self.show_git_diff_gutter,
 2953            show_code_actions: self.show_code_actions,
 2954            show_runnables: self.show_runnables,
 2955            show_breakpoints: self.show_breakpoints,
 2956            git_blame_gutter_max_author_length,
 2957            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2958            placeholder_display_snapshot: self
 2959                .placeholder_display_map
 2960                .as_ref()
 2961                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2962            scroll_anchor: self.scroll_manager.anchor(),
 2963            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2964            is_focused: self.focus_handle.is_focused(window),
 2965            current_line_highlight: self
 2966                .current_line_highlight
 2967                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2968            gutter_hovered: self.gutter_hovered,
 2969        }
 2970    }
 2971
 2972    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2973        self.buffer.read(cx).language_at(point, cx)
 2974    }
 2975
 2976    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2977        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2978    }
 2979
 2980    pub fn active_excerpt(
 2981        &self,
 2982        cx: &App,
 2983    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2984        self.buffer
 2985            .read(cx)
 2986            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2987    }
 2988
 2989    pub fn mode(&self) -> &EditorMode {
 2990        &self.mode
 2991    }
 2992
 2993    pub fn set_mode(&mut self, mode: EditorMode) {
 2994        self.mode = mode;
 2995    }
 2996
 2997    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2998        self.collaboration_hub.as_deref()
 2999    }
 3000
 3001    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 3002        self.collaboration_hub = Some(hub);
 3003    }
 3004
 3005    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3006        self.in_project_search = in_project_search;
 3007    }
 3008
 3009    pub fn set_custom_context_menu(
 3010        &mut self,
 3011        f: impl 'static
 3012        + Fn(
 3013            &mut Self,
 3014            DisplayPoint,
 3015            &mut Window,
 3016            &mut Context<Self>,
 3017        ) -> Option<Entity<ui::ContextMenu>>,
 3018    ) {
 3019        self.custom_context_menu = Some(Box::new(f))
 3020    }
 3021
 3022    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3023        self.completion_provider = provider;
 3024    }
 3025
 3026    #[cfg(any(test, feature = "test-support"))]
 3027    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3028        self.completion_provider.clone()
 3029    }
 3030
 3031    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3032        self.semantics_provider.clone()
 3033    }
 3034
 3035    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3036        self.semantics_provider = provider;
 3037    }
 3038
 3039    pub fn set_edit_prediction_provider<T>(
 3040        &mut self,
 3041        provider: Option<Entity<T>>,
 3042        window: &mut Window,
 3043        cx: &mut Context<Self>,
 3044    ) where
 3045        T: EditPredictionDelegate,
 3046    {
 3047        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3048            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3049                if this.focus_handle.is_focused(window) {
 3050                    this.update_visible_edit_prediction(window, cx);
 3051                }
 3052            }),
 3053            provider: Arc::new(provider),
 3054        });
 3055        self.update_edit_prediction_settings(cx);
 3056        self.refresh_edit_prediction(false, false, window, cx);
 3057    }
 3058
 3059    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3060        self.placeholder_display_map
 3061            .as_ref()
 3062            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3063    }
 3064
 3065    pub fn set_placeholder_text(
 3066        &mut self,
 3067        placeholder_text: &str,
 3068        window: &mut Window,
 3069        cx: &mut Context<Self>,
 3070    ) {
 3071        let multibuffer = cx
 3072            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3073
 3074        let style = window.text_style();
 3075
 3076        self.placeholder_display_map = Some(cx.new(|cx| {
 3077            DisplayMap::new(
 3078                multibuffer,
 3079                style.font(),
 3080                style.font_size.to_pixels(window.rem_size()),
 3081                None,
 3082                FILE_HEADER_HEIGHT,
 3083                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3084                Default::default(),
 3085                DiagnosticSeverity::Off,
 3086                cx,
 3087            )
 3088        }));
 3089        cx.notify();
 3090    }
 3091
 3092    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3093        self.cursor_shape = cursor_shape;
 3094
 3095        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3096        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3097
 3098        cx.notify();
 3099    }
 3100
 3101    pub fn cursor_shape(&self) -> CursorShape {
 3102        self.cursor_shape
 3103    }
 3104
 3105    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3106        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3107    }
 3108
 3109    pub fn set_current_line_highlight(
 3110        &mut self,
 3111        current_line_highlight: Option<CurrentLineHighlight>,
 3112    ) {
 3113        self.current_line_highlight = current_line_highlight;
 3114    }
 3115
 3116    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3117        self.collapse_matches = collapse_matches;
 3118    }
 3119
 3120    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3121        if self.collapse_matches {
 3122            return range.start..range.start;
 3123        }
 3124        range.clone()
 3125    }
 3126
 3127    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3128        self.display_map.read(cx).clip_at_line_ends
 3129    }
 3130
 3131    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3132        if self.display_map.read(cx).clip_at_line_ends != clip {
 3133            self.display_map
 3134                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3135        }
 3136    }
 3137
 3138    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3139        self.input_enabled = input_enabled;
 3140    }
 3141
 3142    pub fn set_edit_predictions_hidden_for_vim_mode(
 3143        &mut self,
 3144        hidden: bool,
 3145        window: &mut Window,
 3146        cx: &mut Context<Self>,
 3147    ) {
 3148        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3149            self.edit_predictions_hidden_for_vim_mode = hidden;
 3150            if hidden {
 3151                self.update_visible_edit_prediction(window, cx);
 3152            } else {
 3153                self.refresh_edit_prediction(true, false, window, cx);
 3154            }
 3155        }
 3156    }
 3157
 3158    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3159        self.menu_edit_predictions_policy = value;
 3160    }
 3161
 3162    pub fn set_autoindent(&mut self, autoindent: bool) {
 3163        if autoindent {
 3164            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3165        } else {
 3166            self.autoindent_mode = None;
 3167        }
 3168    }
 3169
 3170    pub fn read_only(&self, cx: &App) -> bool {
 3171        self.read_only || self.buffer.read(cx).read_only()
 3172    }
 3173
 3174    pub fn set_read_only(&mut self, read_only: bool) {
 3175        self.read_only = read_only;
 3176    }
 3177
 3178    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3179        self.use_autoclose = autoclose;
 3180    }
 3181
 3182    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3183        self.use_auto_surround = auto_surround;
 3184    }
 3185
 3186    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3187        self.auto_replace_emoji_shortcode = auto_replace;
 3188    }
 3189
 3190    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3191        self.buffer_serialization = should_serialize.then(|| {
 3192            BufferSerialization::new(
 3193                ProjectSettings::get_global(cx)
 3194                    .session
 3195                    .restore_unsaved_buffers,
 3196            )
 3197        })
 3198    }
 3199
 3200    fn should_serialize_buffer(&self) -> bool {
 3201        self.buffer_serialization.is_some()
 3202    }
 3203
 3204    pub fn toggle_edit_predictions(
 3205        &mut self,
 3206        _: &ToggleEditPrediction,
 3207        window: &mut Window,
 3208        cx: &mut Context<Self>,
 3209    ) {
 3210        if self.show_edit_predictions_override.is_some() {
 3211            self.set_show_edit_predictions(None, window, cx);
 3212        } else {
 3213            let show_edit_predictions = !self.edit_predictions_enabled();
 3214            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3215        }
 3216    }
 3217
 3218    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3219        self.show_completions_on_input_override = show_completions_on_input;
 3220    }
 3221
 3222    pub fn set_show_edit_predictions(
 3223        &mut self,
 3224        show_edit_predictions: Option<bool>,
 3225        window: &mut Window,
 3226        cx: &mut Context<Self>,
 3227    ) {
 3228        self.show_edit_predictions_override = show_edit_predictions;
 3229        self.update_edit_prediction_settings(cx);
 3230
 3231        if let Some(false) = show_edit_predictions {
 3232            self.discard_edit_prediction(false, cx);
 3233        } else {
 3234            self.refresh_edit_prediction(false, true, window, cx);
 3235        }
 3236    }
 3237
 3238    fn edit_predictions_disabled_in_scope(
 3239        &self,
 3240        buffer: &Entity<Buffer>,
 3241        buffer_position: language::Anchor,
 3242        cx: &App,
 3243    ) -> bool {
 3244        let snapshot = buffer.read(cx).snapshot();
 3245        let settings = snapshot.settings_at(buffer_position, cx);
 3246
 3247        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3248            return false;
 3249        };
 3250
 3251        scope.override_name().is_some_and(|scope_name| {
 3252            settings
 3253                .edit_predictions_disabled_in
 3254                .iter()
 3255                .any(|s| s == scope_name)
 3256        })
 3257    }
 3258
 3259    pub fn set_use_modal_editing(&mut self, to: bool) {
 3260        self.use_modal_editing = to;
 3261    }
 3262
 3263    pub fn use_modal_editing(&self) -> bool {
 3264        self.use_modal_editing
 3265    }
 3266
 3267    fn selections_did_change(
 3268        &mut self,
 3269        local: bool,
 3270        old_cursor_position: &Anchor,
 3271        effects: SelectionEffects,
 3272        window: &mut Window,
 3273        cx: &mut Context<Self>,
 3274    ) {
 3275        window.invalidate_character_coordinates();
 3276
 3277        // Copy selections to primary selection buffer
 3278        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3279        if local {
 3280            let selections = self
 3281                .selections
 3282                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3283            let buffer_handle = self.buffer.read(cx).read(cx);
 3284
 3285            let mut text = String::new();
 3286            for (index, selection) in selections.iter().enumerate() {
 3287                let text_for_selection = buffer_handle
 3288                    .text_for_range(selection.start..selection.end)
 3289                    .collect::<String>();
 3290
 3291                text.push_str(&text_for_selection);
 3292                if index != selections.len() - 1 {
 3293                    text.push('\n');
 3294                }
 3295            }
 3296
 3297            if !text.is_empty() {
 3298                cx.write_to_primary(ClipboardItem::new_string(text));
 3299            }
 3300        }
 3301
 3302        let selection_anchors = self.selections.disjoint_anchors_arc();
 3303
 3304        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3305            self.buffer.update(cx, |buffer, cx| {
 3306                buffer.set_active_selections(
 3307                    &selection_anchors,
 3308                    self.selections.line_mode(),
 3309                    self.cursor_shape,
 3310                    cx,
 3311                )
 3312            });
 3313        }
 3314        let display_map = self
 3315            .display_map
 3316            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3317        let buffer = display_map.buffer_snapshot();
 3318        if self.selections.count() == 1 {
 3319            self.add_selections_state = None;
 3320        }
 3321        self.select_next_state = None;
 3322        self.select_prev_state = None;
 3323        self.select_syntax_node_history.try_clear();
 3324        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3325        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3326        self.take_rename(false, window, cx);
 3327
 3328        let newest_selection = self.selections.newest_anchor();
 3329        let new_cursor_position = newest_selection.head();
 3330        let selection_start = newest_selection.start;
 3331
 3332        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3333            self.push_to_nav_history(
 3334                *old_cursor_position,
 3335                Some(new_cursor_position.to_point(buffer)),
 3336                false,
 3337                effects.nav_history == Some(true),
 3338                cx,
 3339            );
 3340        }
 3341
 3342        if local {
 3343            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3344                self.register_buffer(buffer_id, cx);
 3345            }
 3346
 3347            let mut context_menu = self.context_menu.borrow_mut();
 3348            let completion_menu = match context_menu.as_ref() {
 3349                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3350                Some(CodeContextMenu::CodeActions(_)) => {
 3351                    *context_menu = None;
 3352                    None
 3353                }
 3354                None => None,
 3355            };
 3356            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3357            drop(context_menu);
 3358
 3359            if effects.completions
 3360                && let Some(completion_position) = completion_position
 3361            {
 3362                let start_offset = selection_start.to_offset(buffer);
 3363                let position_matches = start_offset == completion_position.to_offset(buffer);
 3364                let continue_showing = if position_matches {
 3365                    if self.snippet_stack.is_empty() {
 3366                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3367                            == Some(CharKind::Word)
 3368                    } else {
 3369                        // Snippet choices can be shown even when the cursor is in whitespace.
 3370                        // Dismissing the menu with actions like backspace is handled by
 3371                        // invalidation regions.
 3372                        true
 3373                    }
 3374                } else {
 3375                    false
 3376                };
 3377
 3378                if continue_showing {
 3379                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3380                } else {
 3381                    self.hide_context_menu(window, cx);
 3382                }
 3383            }
 3384
 3385            hide_hover(self, cx);
 3386
 3387            if old_cursor_position.to_display_point(&display_map).row()
 3388                != new_cursor_position.to_display_point(&display_map).row()
 3389            {
 3390                self.available_code_actions.take();
 3391            }
 3392            self.refresh_code_actions(window, cx);
 3393            self.refresh_document_highlights(cx);
 3394            refresh_linked_ranges(self, window, cx);
 3395
 3396            self.refresh_selected_text_highlights(false, window, cx);
 3397            self.refresh_matching_bracket_highlights(window, cx);
 3398            self.update_visible_edit_prediction(window, cx);
 3399            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3400            self.inline_blame_popover.take();
 3401            if self.git_blame_inline_enabled {
 3402                self.start_inline_blame_timer(window, cx);
 3403            }
 3404        }
 3405
 3406        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3407        cx.emit(EditorEvent::SelectionsChanged { local });
 3408
 3409        let selections = &self.selections.disjoint_anchors_arc();
 3410        if selections.len() == 1 {
 3411            cx.emit(SearchEvent::ActiveMatchChanged)
 3412        }
 3413        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3414            let inmemory_selections = selections
 3415                .iter()
 3416                .map(|s| {
 3417                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3418                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3419                })
 3420                .collect();
 3421            self.update_restoration_data(cx, |data| {
 3422                data.selections = inmemory_selections;
 3423            });
 3424
 3425            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3426                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3427            {
 3428                let snapshot = self.buffer().read(cx).snapshot(cx);
 3429                let selections = selections.clone();
 3430                let background_executor = cx.background_executor().clone();
 3431                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3432                self.serialize_selections = cx.background_spawn(async move {
 3433                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3434                    let db_selections = selections
 3435                        .iter()
 3436                        .map(|selection| {
 3437                            (
 3438                                selection.start.to_offset(&snapshot).0,
 3439                                selection.end.to_offset(&snapshot).0,
 3440                            )
 3441                        })
 3442                        .collect();
 3443
 3444                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3445                        .await
 3446                        .with_context(|| {
 3447                            format!(
 3448                                "persisting editor selections for editor {editor_id}, \
 3449                                workspace {workspace_id:?}"
 3450                            )
 3451                        })
 3452                        .log_err();
 3453                });
 3454            }
 3455        }
 3456
 3457        cx.notify();
 3458    }
 3459
 3460    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3461        use text::ToOffset as _;
 3462        use text::ToPoint as _;
 3463
 3464        if self.mode.is_minimap()
 3465            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3466        {
 3467            return;
 3468        }
 3469
 3470        if !self.buffer().read(cx).is_singleton() {
 3471            return;
 3472        }
 3473
 3474        let display_snapshot = self
 3475            .display_map
 3476            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3477        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3478            return;
 3479        };
 3480        let inmemory_folds = display_snapshot
 3481            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3482            .map(|fold| {
 3483                fold.range.start.text_anchor.to_point(&snapshot)
 3484                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3485            })
 3486            .collect();
 3487        self.update_restoration_data(cx, |data| {
 3488            data.folds = inmemory_folds;
 3489        });
 3490
 3491        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3492            return;
 3493        };
 3494        let background_executor = cx.background_executor().clone();
 3495        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3496        let db_folds = display_snapshot
 3497            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3498            .map(|fold| {
 3499                (
 3500                    fold.range.start.text_anchor.to_offset(&snapshot),
 3501                    fold.range.end.text_anchor.to_offset(&snapshot),
 3502                )
 3503            })
 3504            .collect();
 3505        self.serialize_folds = cx.background_spawn(async move {
 3506            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3507            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3508                .await
 3509                .with_context(|| {
 3510                    format!(
 3511                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3512                    )
 3513                })
 3514                .log_err();
 3515        });
 3516    }
 3517
 3518    pub fn sync_selections(
 3519        &mut self,
 3520        other: Entity<Editor>,
 3521        cx: &mut Context<Self>,
 3522    ) -> gpui::Subscription {
 3523        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3524        if !other_selections.is_empty() {
 3525            self.selections
 3526                .change_with(&self.display_snapshot(cx), |selections| {
 3527                    selections.select_anchors(other_selections);
 3528                });
 3529        }
 3530
 3531        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3532            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3533                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3534                if other_selections.is_empty() {
 3535                    return;
 3536                }
 3537                let snapshot = this.display_snapshot(cx);
 3538                this.selections.change_with(&snapshot, |selections| {
 3539                    selections.select_anchors(other_selections);
 3540                });
 3541            }
 3542        });
 3543
 3544        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3545            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3546                let these_selections = this.selections.disjoint_anchors().to_vec();
 3547                if these_selections.is_empty() {
 3548                    return;
 3549                }
 3550                other.update(cx, |other_editor, cx| {
 3551                    let snapshot = other_editor.display_snapshot(cx);
 3552                    other_editor
 3553                        .selections
 3554                        .change_with(&snapshot, |selections| {
 3555                            selections.select_anchors(these_selections);
 3556                        })
 3557                });
 3558            }
 3559        });
 3560
 3561        Subscription::join(other_subscription, this_subscription)
 3562    }
 3563
 3564    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3565        if self.buffer().read(cx).is_singleton() {
 3566            return;
 3567        }
 3568        let snapshot = self.buffer.read(cx).snapshot(cx);
 3569        let buffer_ids: HashSet<BufferId> = self
 3570            .selections
 3571            .disjoint_anchor_ranges()
 3572            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3573            .collect();
 3574        for buffer_id in buffer_ids {
 3575            self.unfold_buffer(buffer_id, cx);
 3576        }
 3577    }
 3578
 3579    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3580    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3581    /// effects of selection change occur at the end of the transaction.
 3582    pub fn change_selections<R>(
 3583        &mut self,
 3584        effects: SelectionEffects,
 3585        window: &mut Window,
 3586        cx: &mut Context<Self>,
 3587        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3588    ) -> R {
 3589        let snapshot = self.display_snapshot(cx);
 3590        if let Some(state) = &mut self.deferred_selection_effects_state {
 3591            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3592            state.effects.completions = effects.completions;
 3593            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3594            let (changed, result) = self.selections.change_with(&snapshot, change);
 3595            state.changed |= changed;
 3596            return result;
 3597        }
 3598        let mut state = DeferredSelectionEffectsState {
 3599            changed: false,
 3600            effects,
 3601            old_cursor_position: self.selections.newest_anchor().head(),
 3602            history_entry: SelectionHistoryEntry {
 3603                selections: self.selections.disjoint_anchors_arc(),
 3604                select_next_state: self.select_next_state.clone(),
 3605                select_prev_state: self.select_prev_state.clone(),
 3606                add_selections_state: self.add_selections_state.clone(),
 3607            },
 3608        };
 3609        let (changed, result) = self.selections.change_with(&snapshot, change);
 3610        state.changed = state.changed || changed;
 3611        if self.defer_selection_effects {
 3612            self.deferred_selection_effects_state = Some(state);
 3613        } else {
 3614            self.apply_selection_effects(state, window, cx);
 3615        }
 3616        result
 3617    }
 3618
 3619    /// Defers the effects of selection change, so that the effects of multiple calls to
 3620    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3621    /// to selection history and the state of popovers based on selection position aren't
 3622    /// erroneously updated.
 3623    pub fn with_selection_effects_deferred<R>(
 3624        &mut self,
 3625        window: &mut Window,
 3626        cx: &mut Context<Self>,
 3627        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3628    ) -> R {
 3629        let already_deferred = self.defer_selection_effects;
 3630        self.defer_selection_effects = true;
 3631        let result = update(self, window, cx);
 3632        if !already_deferred {
 3633            self.defer_selection_effects = false;
 3634            if let Some(state) = self.deferred_selection_effects_state.take() {
 3635                self.apply_selection_effects(state, window, cx);
 3636            }
 3637        }
 3638        result
 3639    }
 3640
 3641    fn apply_selection_effects(
 3642        &mut self,
 3643        state: DeferredSelectionEffectsState,
 3644        window: &mut Window,
 3645        cx: &mut Context<Self>,
 3646    ) {
 3647        if state.changed {
 3648            self.selection_history.push(state.history_entry);
 3649
 3650            if let Some(autoscroll) = state.effects.scroll {
 3651                self.request_autoscroll(autoscroll, cx);
 3652            }
 3653
 3654            let old_cursor_position = &state.old_cursor_position;
 3655
 3656            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3657
 3658            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3659                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3660            }
 3661        }
 3662    }
 3663
 3664    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3665    where
 3666        I: IntoIterator<Item = (Range<S>, T)>,
 3667        S: ToOffset,
 3668        T: Into<Arc<str>>,
 3669    {
 3670        if self.read_only(cx) {
 3671            return;
 3672        }
 3673
 3674        self.buffer
 3675            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3676    }
 3677
 3678    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3679    where
 3680        I: IntoIterator<Item = (Range<S>, T)>,
 3681        S: ToOffset,
 3682        T: Into<Arc<str>>,
 3683    {
 3684        if self.read_only(cx) {
 3685            return;
 3686        }
 3687
 3688        self.buffer.update(cx, |buffer, cx| {
 3689            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3690        });
 3691    }
 3692
 3693    pub fn edit_with_block_indent<I, S, T>(
 3694        &mut self,
 3695        edits: I,
 3696        original_indent_columns: Vec<Option<u32>>,
 3697        cx: &mut Context<Self>,
 3698    ) where
 3699        I: IntoIterator<Item = (Range<S>, T)>,
 3700        S: ToOffset,
 3701        T: Into<Arc<str>>,
 3702    {
 3703        if self.read_only(cx) {
 3704            return;
 3705        }
 3706
 3707        self.buffer.update(cx, |buffer, cx| {
 3708            buffer.edit(
 3709                edits,
 3710                Some(AutoindentMode::Block {
 3711                    original_indent_columns,
 3712                }),
 3713                cx,
 3714            )
 3715        });
 3716    }
 3717
 3718    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3719        self.hide_context_menu(window, cx);
 3720
 3721        match phase {
 3722            SelectPhase::Begin {
 3723                position,
 3724                add,
 3725                click_count,
 3726            } => self.begin_selection(position, add, click_count, window, cx),
 3727            SelectPhase::BeginColumnar {
 3728                position,
 3729                goal_column,
 3730                reset,
 3731                mode,
 3732            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3733            SelectPhase::Extend {
 3734                position,
 3735                click_count,
 3736            } => self.extend_selection(position, click_count, window, cx),
 3737            SelectPhase::Update {
 3738                position,
 3739                goal_column,
 3740                scroll_delta,
 3741            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3742            SelectPhase::End => self.end_selection(window, cx),
 3743        }
 3744    }
 3745
 3746    fn extend_selection(
 3747        &mut self,
 3748        position: DisplayPoint,
 3749        click_count: usize,
 3750        window: &mut Window,
 3751        cx: &mut Context<Self>,
 3752    ) {
 3753        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3754        let tail = self
 3755            .selections
 3756            .newest::<MultiBufferOffset>(&display_map)
 3757            .tail();
 3758        let click_count = click_count.max(match self.selections.select_mode() {
 3759            SelectMode::Character => 1,
 3760            SelectMode::Word(_) => 2,
 3761            SelectMode::Line(_) => 3,
 3762            SelectMode::All => 4,
 3763        });
 3764        self.begin_selection(position, false, click_count, window, cx);
 3765
 3766        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3767
 3768        let current_selection = match self.selections.select_mode() {
 3769            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3770            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3771        };
 3772
 3773        let mut pending_selection = self
 3774            .selections
 3775            .pending_anchor()
 3776            .cloned()
 3777            .expect("extend_selection not called with pending selection");
 3778
 3779        if pending_selection
 3780            .start
 3781            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3782            == Ordering::Greater
 3783        {
 3784            pending_selection.start = current_selection.start;
 3785        }
 3786        if pending_selection
 3787            .end
 3788            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3789            == Ordering::Less
 3790        {
 3791            pending_selection.end = current_selection.end;
 3792            pending_selection.reversed = true;
 3793        }
 3794
 3795        let mut pending_mode = self.selections.pending_mode().unwrap();
 3796        match &mut pending_mode {
 3797            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3798            _ => {}
 3799        }
 3800
 3801        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3802            SelectionEffects::scroll(Autoscroll::fit())
 3803        } else {
 3804            SelectionEffects::no_scroll()
 3805        };
 3806
 3807        self.change_selections(effects, window, cx, |s| {
 3808            s.set_pending(pending_selection.clone(), pending_mode);
 3809            s.set_is_extending(true);
 3810        });
 3811    }
 3812
 3813    fn begin_selection(
 3814        &mut self,
 3815        position: DisplayPoint,
 3816        add: bool,
 3817        click_count: usize,
 3818        window: &mut Window,
 3819        cx: &mut Context<Self>,
 3820    ) {
 3821        if !self.focus_handle.is_focused(window) {
 3822            self.last_focused_descendant = None;
 3823            window.focus(&self.focus_handle);
 3824        }
 3825
 3826        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3827        let buffer = display_map.buffer_snapshot();
 3828        let position = display_map.clip_point(position, Bias::Left);
 3829
 3830        let start;
 3831        let end;
 3832        let mode;
 3833        let mut auto_scroll;
 3834        match click_count {
 3835            1 => {
 3836                start = buffer.anchor_before(position.to_point(&display_map));
 3837                end = start;
 3838                mode = SelectMode::Character;
 3839                auto_scroll = true;
 3840            }
 3841            2 => {
 3842                let position = display_map
 3843                    .clip_point(position, Bias::Left)
 3844                    .to_offset(&display_map, Bias::Left);
 3845                let (range, _) = buffer.surrounding_word(position, None);
 3846                start = buffer.anchor_before(range.start);
 3847                end = buffer.anchor_before(range.end);
 3848                mode = SelectMode::Word(start..end);
 3849                auto_scroll = true;
 3850            }
 3851            3 => {
 3852                let position = display_map
 3853                    .clip_point(position, Bias::Left)
 3854                    .to_point(&display_map);
 3855                let line_start = display_map.prev_line_boundary(position).0;
 3856                let next_line_start = buffer.clip_point(
 3857                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3858                    Bias::Left,
 3859                );
 3860                start = buffer.anchor_before(line_start);
 3861                end = buffer.anchor_before(next_line_start);
 3862                mode = SelectMode::Line(start..end);
 3863                auto_scroll = true;
 3864            }
 3865            _ => {
 3866                start = buffer.anchor_before(MultiBufferOffset(0));
 3867                end = buffer.anchor_before(buffer.len());
 3868                mode = SelectMode::All;
 3869                auto_scroll = false;
 3870            }
 3871        }
 3872        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3873
 3874        let point_to_delete: Option<usize> = {
 3875            let selected_points: Vec<Selection<Point>> =
 3876                self.selections.disjoint_in_range(start..end, &display_map);
 3877
 3878            if !add || click_count > 1 {
 3879                None
 3880            } else if !selected_points.is_empty() {
 3881                Some(selected_points[0].id)
 3882            } else {
 3883                let clicked_point_already_selected =
 3884                    self.selections.disjoint_anchors().iter().find(|selection| {
 3885                        selection.start.to_point(buffer) == start.to_point(buffer)
 3886                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3887                    });
 3888
 3889                clicked_point_already_selected.map(|selection| selection.id)
 3890            }
 3891        };
 3892
 3893        let selections_count = self.selections.count();
 3894        let effects = if auto_scroll {
 3895            SelectionEffects::default()
 3896        } else {
 3897            SelectionEffects::no_scroll()
 3898        };
 3899
 3900        self.change_selections(effects, window, cx, |s| {
 3901            if let Some(point_to_delete) = point_to_delete {
 3902                s.delete(point_to_delete);
 3903
 3904                if selections_count == 1 {
 3905                    s.set_pending_anchor_range(start..end, mode);
 3906                }
 3907            } else {
 3908                if !add {
 3909                    s.clear_disjoint();
 3910                }
 3911
 3912                s.set_pending_anchor_range(start..end, mode);
 3913            }
 3914        });
 3915    }
 3916
 3917    fn begin_columnar_selection(
 3918        &mut self,
 3919        position: DisplayPoint,
 3920        goal_column: u32,
 3921        reset: bool,
 3922        mode: ColumnarMode,
 3923        window: &mut Window,
 3924        cx: &mut Context<Self>,
 3925    ) {
 3926        if !self.focus_handle.is_focused(window) {
 3927            self.last_focused_descendant = None;
 3928            window.focus(&self.focus_handle);
 3929        }
 3930
 3931        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3932
 3933        if reset {
 3934            let pointer_position = display_map
 3935                .buffer_snapshot()
 3936                .anchor_before(position.to_point(&display_map));
 3937
 3938            self.change_selections(
 3939                SelectionEffects::scroll(Autoscroll::newest()),
 3940                window,
 3941                cx,
 3942                |s| {
 3943                    s.clear_disjoint();
 3944                    s.set_pending_anchor_range(
 3945                        pointer_position..pointer_position,
 3946                        SelectMode::Character,
 3947                    );
 3948                },
 3949            );
 3950        };
 3951
 3952        let tail = self.selections.newest::<Point>(&display_map).tail();
 3953        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3954        self.columnar_selection_state = match mode {
 3955            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3956                selection_tail: selection_anchor,
 3957                display_point: if reset {
 3958                    if position.column() != goal_column {
 3959                        Some(DisplayPoint::new(position.row(), goal_column))
 3960                    } else {
 3961                        None
 3962                    }
 3963                } else {
 3964                    None
 3965                },
 3966            }),
 3967            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3968                selection_tail: selection_anchor,
 3969            }),
 3970        };
 3971
 3972        if !reset {
 3973            self.select_columns(position, goal_column, &display_map, window, cx);
 3974        }
 3975    }
 3976
 3977    fn update_selection(
 3978        &mut self,
 3979        position: DisplayPoint,
 3980        goal_column: u32,
 3981        scroll_delta: gpui::Point<f32>,
 3982        window: &mut Window,
 3983        cx: &mut Context<Self>,
 3984    ) {
 3985        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3986
 3987        if self.columnar_selection_state.is_some() {
 3988            self.select_columns(position, goal_column, &display_map, window, cx);
 3989        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3990            let buffer = display_map.buffer_snapshot();
 3991            let head;
 3992            let tail;
 3993            let mode = self.selections.pending_mode().unwrap();
 3994            match &mode {
 3995                SelectMode::Character => {
 3996                    head = position.to_point(&display_map);
 3997                    tail = pending.tail().to_point(buffer);
 3998                }
 3999                SelectMode::Word(original_range) => {
 4000                    let offset = display_map
 4001                        .clip_point(position, Bias::Left)
 4002                        .to_offset(&display_map, Bias::Left);
 4003                    let original_range = original_range.to_offset(buffer);
 4004
 4005                    let head_offset = if buffer.is_inside_word(offset, None)
 4006                        || original_range.contains(&offset)
 4007                    {
 4008                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4009                        if word_range.start < original_range.start {
 4010                            word_range.start
 4011                        } else {
 4012                            word_range.end
 4013                        }
 4014                    } else {
 4015                        offset
 4016                    };
 4017
 4018                    head = head_offset.to_point(buffer);
 4019                    if head_offset <= original_range.start {
 4020                        tail = original_range.end.to_point(buffer);
 4021                    } else {
 4022                        tail = original_range.start.to_point(buffer);
 4023                    }
 4024                }
 4025                SelectMode::Line(original_range) => {
 4026                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4027
 4028                    let position = display_map
 4029                        .clip_point(position, Bias::Left)
 4030                        .to_point(&display_map);
 4031                    let line_start = display_map.prev_line_boundary(position).0;
 4032                    let next_line_start = buffer.clip_point(
 4033                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4034                        Bias::Left,
 4035                    );
 4036
 4037                    if line_start < original_range.start {
 4038                        head = line_start
 4039                    } else {
 4040                        head = next_line_start
 4041                    }
 4042
 4043                    if head <= original_range.start {
 4044                        tail = original_range.end;
 4045                    } else {
 4046                        tail = original_range.start;
 4047                    }
 4048                }
 4049                SelectMode::All => {
 4050                    return;
 4051                }
 4052            };
 4053
 4054            if head < tail {
 4055                pending.start = buffer.anchor_before(head);
 4056                pending.end = buffer.anchor_before(tail);
 4057                pending.reversed = true;
 4058            } else {
 4059                pending.start = buffer.anchor_before(tail);
 4060                pending.end = buffer.anchor_before(head);
 4061                pending.reversed = false;
 4062            }
 4063
 4064            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4065                s.set_pending(pending.clone(), mode);
 4066            });
 4067        } else {
 4068            log::error!("update_selection dispatched with no pending selection");
 4069            return;
 4070        }
 4071
 4072        self.apply_scroll_delta(scroll_delta, window, cx);
 4073        cx.notify();
 4074    }
 4075
 4076    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4077        self.columnar_selection_state.take();
 4078        if let Some(pending_mode) = self.selections.pending_mode() {
 4079            let selections = self
 4080                .selections
 4081                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4082            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4083                s.select(selections);
 4084                s.clear_pending();
 4085                if s.is_extending() {
 4086                    s.set_is_extending(false);
 4087                } else {
 4088                    s.set_select_mode(pending_mode);
 4089                }
 4090            });
 4091        }
 4092    }
 4093
 4094    fn select_columns(
 4095        &mut self,
 4096        head: DisplayPoint,
 4097        goal_column: u32,
 4098        display_map: &DisplaySnapshot,
 4099        window: &mut Window,
 4100        cx: &mut Context<Self>,
 4101    ) {
 4102        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4103            return;
 4104        };
 4105
 4106        let tail = match columnar_state {
 4107            ColumnarSelectionState::FromMouse {
 4108                selection_tail,
 4109                display_point,
 4110            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4111            ColumnarSelectionState::FromSelection { selection_tail } => {
 4112                selection_tail.to_display_point(display_map)
 4113            }
 4114        };
 4115
 4116        let start_row = cmp::min(tail.row(), head.row());
 4117        let end_row = cmp::max(tail.row(), head.row());
 4118        let start_column = cmp::min(tail.column(), goal_column);
 4119        let end_column = cmp::max(tail.column(), goal_column);
 4120        let reversed = start_column < tail.column();
 4121
 4122        let selection_ranges = (start_row.0..=end_row.0)
 4123            .map(DisplayRow)
 4124            .filter_map(|row| {
 4125                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4126                    || start_column <= display_map.line_len(row))
 4127                    && !display_map.is_block_line(row)
 4128                {
 4129                    let start = display_map
 4130                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4131                        .to_point(display_map);
 4132                    let end = display_map
 4133                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4134                        .to_point(display_map);
 4135                    if reversed {
 4136                        Some(end..start)
 4137                    } else {
 4138                        Some(start..end)
 4139                    }
 4140                } else {
 4141                    None
 4142                }
 4143            })
 4144            .collect::<Vec<_>>();
 4145        if selection_ranges.is_empty() {
 4146            return;
 4147        }
 4148
 4149        let ranges = match columnar_state {
 4150            ColumnarSelectionState::FromMouse { .. } => {
 4151                let mut non_empty_ranges = selection_ranges
 4152                    .iter()
 4153                    .filter(|selection_range| selection_range.start != selection_range.end)
 4154                    .peekable();
 4155                if non_empty_ranges.peek().is_some() {
 4156                    non_empty_ranges.cloned().collect()
 4157                } else {
 4158                    selection_ranges
 4159                }
 4160            }
 4161            _ => selection_ranges,
 4162        };
 4163
 4164        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4165            s.select_ranges(ranges);
 4166        });
 4167        cx.notify();
 4168    }
 4169
 4170    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4171        self.selections
 4172            .all_adjusted(snapshot)
 4173            .iter()
 4174            .any(|selection| !selection.is_empty())
 4175    }
 4176
 4177    pub fn has_pending_nonempty_selection(&self) -> bool {
 4178        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4179            Some(Selection { start, end, .. }) => start != end,
 4180            None => false,
 4181        };
 4182
 4183        pending_nonempty_selection
 4184            || (self.columnar_selection_state.is_some()
 4185                && self.selections.disjoint_anchors().len() > 1)
 4186    }
 4187
 4188    pub fn has_pending_selection(&self) -> bool {
 4189        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4190    }
 4191
 4192    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4193        self.selection_mark_mode = false;
 4194        self.selection_drag_state = SelectionDragState::None;
 4195
 4196        if self.dismiss_menus_and_popups(true, window, cx) {
 4197            cx.notify();
 4198            return;
 4199        }
 4200        if self.clear_expanded_diff_hunks(cx) {
 4201            cx.notify();
 4202            return;
 4203        }
 4204        if self.show_git_blame_gutter {
 4205            self.show_git_blame_gutter = false;
 4206            cx.notify();
 4207            return;
 4208        }
 4209
 4210        if self.mode.is_full()
 4211            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4212        {
 4213            cx.notify();
 4214            return;
 4215        }
 4216
 4217        cx.propagate();
 4218    }
 4219
 4220    pub fn dismiss_menus_and_popups(
 4221        &mut self,
 4222        is_user_requested: bool,
 4223        window: &mut Window,
 4224        cx: &mut Context<Self>,
 4225    ) -> bool {
 4226        let mut dismissed = false;
 4227
 4228        dismissed |= self.take_rename(false, window, cx).is_some();
 4229        dismissed |= self.hide_blame_popover(true, cx);
 4230        dismissed |= hide_hover(self, cx);
 4231        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4232        dismissed |= self.hide_context_menu(window, cx).is_some();
 4233        dismissed |= self.mouse_context_menu.take().is_some();
 4234        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4235        dismissed |= self.snippet_stack.pop().is_some();
 4236
 4237        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4238            self.dismiss_diagnostics(cx);
 4239            dismissed = true;
 4240        }
 4241
 4242        dismissed
 4243    }
 4244
 4245    fn linked_editing_ranges_for(
 4246        &self,
 4247        selection: Range<text::Anchor>,
 4248        cx: &App,
 4249    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4250        if self.linked_edit_ranges.is_empty() {
 4251            return None;
 4252        }
 4253        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4254            selection.end.buffer_id.and_then(|end_buffer_id| {
 4255                if selection.start.buffer_id != Some(end_buffer_id) {
 4256                    return None;
 4257                }
 4258                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4259                let snapshot = buffer.read(cx).snapshot();
 4260                self.linked_edit_ranges
 4261                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4262                    .map(|ranges| (ranges, snapshot, buffer))
 4263            })?;
 4264        use text::ToOffset as TO;
 4265        // find offset from the start of current range to current cursor position
 4266        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4267
 4268        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4269        let start_difference = start_offset - start_byte_offset;
 4270        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4271        let end_difference = end_offset - start_byte_offset;
 4272        // Current range has associated linked ranges.
 4273        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4274        for range in linked_ranges.iter() {
 4275            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4276            let end_offset = start_offset + end_difference;
 4277            let start_offset = start_offset + start_difference;
 4278            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4279                continue;
 4280            }
 4281            if self.selections.disjoint_anchor_ranges().any(|s| {
 4282                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4283                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4284                {
 4285                    return false;
 4286                }
 4287                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4288                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4289            }) {
 4290                continue;
 4291            }
 4292            let start = buffer_snapshot.anchor_after(start_offset);
 4293            let end = buffer_snapshot.anchor_after(end_offset);
 4294            linked_edits
 4295                .entry(buffer.clone())
 4296                .or_default()
 4297                .push(start..end);
 4298        }
 4299        Some(linked_edits)
 4300    }
 4301
 4302    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4303        let text: Arc<str> = text.into();
 4304
 4305        if self.read_only(cx) {
 4306            return;
 4307        }
 4308
 4309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4310
 4311        self.unfold_buffers_with_selections(cx);
 4312
 4313        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4314        let mut bracket_inserted = false;
 4315        let mut edits = Vec::new();
 4316        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4317        let mut new_selections = Vec::with_capacity(selections.len());
 4318        let mut new_autoclose_regions = Vec::new();
 4319        let snapshot = self.buffer.read(cx).read(cx);
 4320        let mut clear_linked_edit_ranges = false;
 4321
 4322        for (selection, autoclose_region) in
 4323            self.selections_with_autoclose_regions(selections, &snapshot)
 4324        {
 4325            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4326                // Determine if the inserted text matches the opening or closing
 4327                // bracket of any of this language's bracket pairs.
 4328                let mut bracket_pair = None;
 4329                let mut is_bracket_pair_start = false;
 4330                let mut is_bracket_pair_end = false;
 4331                if !text.is_empty() {
 4332                    let mut bracket_pair_matching_end = None;
 4333                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4334                    //  and they are removing the character that triggered IME popup.
 4335                    for (pair, enabled) in scope.brackets() {
 4336                        if !pair.close && !pair.surround {
 4337                            continue;
 4338                        }
 4339
 4340                        if enabled && pair.start.ends_with(text.as_ref()) {
 4341                            let prefix_len = pair.start.len() - text.len();
 4342                            let preceding_text_matches_prefix = prefix_len == 0
 4343                                || (selection.start.column >= (prefix_len as u32)
 4344                                    && snapshot.contains_str_at(
 4345                                        Point::new(
 4346                                            selection.start.row,
 4347                                            selection.start.column - (prefix_len as u32),
 4348                                        ),
 4349                                        &pair.start[..prefix_len],
 4350                                    ));
 4351                            if preceding_text_matches_prefix {
 4352                                bracket_pair = Some(pair.clone());
 4353                                is_bracket_pair_start = true;
 4354                                break;
 4355                            }
 4356                        }
 4357                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4358                        {
 4359                            // take first bracket pair matching end, but don't break in case a later bracket
 4360                            // pair matches start
 4361                            bracket_pair_matching_end = Some(pair.clone());
 4362                        }
 4363                    }
 4364                    if let Some(end) = bracket_pair_matching_end
 4365                        && bracket_pair.is_none()
 4366                    {
 4367                        bracket_pair = Some(end);
 4368                        is_bracket_pair_end = true;
 4369                    }
 4370                }
 4371
 4372                if let Some(bracket_pair) = bracket_pair {
 4373                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4374                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4375                    let auto_surround =
 4376                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4377                    if selection.is_empty() {
 4378                        if is_bracket_pair_start {
 4379                            // If the inserted text is a suffix of an opening bracket and the
 4380                            // selection is preceded by the rest of the opening bracket, then
 4381                            // insert the closing bracket.
 4382                            let following_text_allows_autoclose = snapshot
 4383                                .chars_at(selection.start)
 4384                                .next()
 4385                                .is_none_or(|c| scope.should_autoclose_before(c));
 4386
 4387                            let preceding_text_allows_autoclose = selection.start.column == 0
 4388                                || snapshot
 4389                                    .reversed_chars_at(selection.start)
 4390                                    .next()
 4391                                    .is_none_or(|c| {
 4392                                        bracket_pair.start != bracket_pair.end
 4393                                            || !snapshot
 4394                                                .char_classifier_at(selection.start)
 4395                                                .is_word(c)
 4396                                    });
 4397
 4398                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4399                                && bracket_pair.start.len() == 1
 4400                            {
 4401                                let target = bracket_pair.start.chars().next().unwrap();
 4402                                let current_line_count = snapshot
 4403                                    .reversed_chars_at(selection.start)
 4404                                    .take_while(|&c| c != '\n')
 4405                                    .filter(|&c| c == target)
 4406                                    .count();
 4407                                current_line_count % 2 == 1
 4408                            } else {
 4409                                false
 4410                            };
 4411
 4412                            if autoclose
 4413                                && bracket_pair.close
 4414                                && following_text_allows_autoclose
 4415                                && preceding_text_allows_autoclose
 4416                                && !is_closing_quote
 4417                            {
 4418                                let anchor = snapshot.anchor_before(selection.end);
 4419                                new_selections.push((selection.map(|_| anchor), text.len()));
 4420                                new_autoclose_regions.push((
 4421                                    anchor,
 4422                                    text.len(),
 4423                                    selection.id,
 4424                                    bracket_pair.clone(),
 4425                                ));
 4426                                edits.push((
 4427                                    selection.range(),
 4428                                    format!("{}{}", text, bracket_pair.end).into(),
 4429                                ));
 4430                                bracket_inserted = true;
 4431                                continue;
 4432                            }
 4433                        }
 4434
 4435                        if let Some(region) = autoclose_region {
 4436                            // If the selection is followed by an auto-inserted closing bracket,
 4437                            // then don't insert that closing bracket again; just move the selection
 4438                            // past the closing bracket.
 4439                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4440                                && text.as_ref() == region.pair.end.as_str()
 4441                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4442                            if should_skip {
 4443                                let anchor = snapshot.anchor_after(selection.end);
 4444                                new_selections
 4445                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4446                                continue;
 4447                            }
 4448                        }
 4449
 4450                        let always_treat_brackets_as_autoclosed = snapshot
 4451                            .language_settings_at(selection.start, cx)
 4452                            .always_treat_brackets_as_autoclosed;
 4453                        if always_treat_brackets_as_autoclosed
 4454                            && is_bracket_pair_end
 4455                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4456                        {
 4457                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4458                            // and the inserted text is a closing bracket and the selection is followed
 4459                            // by the closing bracket then move the selection past the closing bracket.
 4460                            let anchor = snapshot.anchor_after(selection.end);
 4461                            new_selections.push((selection.map(|_| anchor), text.len()));
 4462                            continue;
 4463                        }
 4464                    }
 4465                    // If an opening bracket is 1 character long and is typed while
 4466                    // text is selected, then surround that text with the bracket pair.
 4467                    else if auto_surround
 4468                        && bracket_pair.surround
 4469                        && is_bracket_pair_start
 4470                        && bracket_pair.start.chars().count() == 1
 4471                    {
 4472                        edits.push((selection.start..selection.start, text.clone()));
 4473                        edits.push((
 4474                            selection.end..selection.end,
 4475                            bracket_pair.end.as_str().into(),
 4476                        ));
 4477                        bracket_inserted = true;
 4478                        new_selections.push((
 4479                            Selection {
 4480                                id: selection.id,
 4481                                start: snapshot.anchor_after(selection.start),
 4482                                end: snapshot.anchor_before(selection.end),
 4483                                reversed: selection.reversed,
 4484                                goal: selection.goal,
 4485                            },
 4486                            0,
 4487                        ));
 4488                        continue;
 4489                    }
 4490                }
 4491            }
 4492
 4493            if self.auto_replace_emoji_shortcode
 4494                && selection.is_empty()
 4495                && text.as_ref().ends_with(':')
 4496                && let Some(possible_emoji_short_code) =
 4497                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4498                && !possible_emoji_short_code.is_empty()
 4499                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4500            {
 4501                let emoji_shortcode_start = Point::new(
 4502                    selection.start.row,
 4503                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4504                );
 4505
 4506                // Remove shortcode from buffer
 4507                edits.push((
 4508                    emoji_shortcode_start..selection.start,
 4509                    "".to_string().into(),
 4510                ));
 4511                new_selections.push((
 4512                    Selection {
 4513                        id: selection.id,
 4514                        start: snapshot.anchor_after(emoji_shortcode_start),
 4515                        end: snapshot.anchor_before(selection.start),
 4516                        reversed: selection.reversed,
 4517                        goal: selection.goal,
 4518                    },
 4519                    0,
 4520                ));
 4521
 4522                // Insert emoji
 4523                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4524                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4525                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4526
 4527                continue;
 4528            }
 4529
 4530            // If not handling any auto-close operation, then just replace the selected
 4531            // text with the given input and move the selection to the end of the
 4532            // newly inserted text.
 4533            let anchor = snapshot.anchor_after(selection.end);
 4534            if !self.linked_edit_ranges.is_empty() {
 4535                let start_anchor = snapshot.anchor_before(selection.start);
 4536
 4537                let is_word_char = text.chars().next().is_none_or(|char| {
 4538                    let classifier = snapshot
 4539                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4540                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4541                    classifier.is_word(char)
 4542                });
 4543
 4544                if is_word_char {
 4545                    if let Some(ranges) = self
 4546                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4547                    {
 4548                        for (buffer, edits) in ranges {
 4549                            linked_edits
 4550                                .entry(buffer.clone())
 4551                                .or_default()
 4552                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4553                        }
 4554                    }
 4555                } else {
 4556                    clear_linked_edit_ranges = true;
 4557                }
 4558            }
 4559
 4560            new_selections.push((selection.map(|_| anchor), 0));
 4561            edits.push((selection.start..selection.end, text.clone()));
 4562        }
 4563
 4564        drop(snapshot);
 4565
 4566        self.transact(window, cx, |this, window, cx| {
 4567            if clear_linked_edit_ranges {
 4568                this.linked_edit_ranges.clear();
 4569            }
 4570            let initial_buffer_versions =
 4571                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4572
 4573            this.buffer.update(cx, |buffer, cx| {
 4574                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4575            });
 4576            for (buffer, edits) in linked_edits {
 4577                buffer.update(cx, |buffer, cx| {
 4578                    let snapshot = buffer.snapshot();
 4579                    let edits = edits
 4580                        .into_iter()
 4581                        .map(|(range, text)| {
 4582                            use text::ToPoint as TP;
 4583                            let end_point = TP::to_point(&range.end, &snapshot);
 4584                            let start_point = TP::to_point(&range.start, &snapshot);
 4585                            (start_point..end_point, text)
 4586                        })
 4587                        .sorted_by_key(|(range, _)| range.start);
 4588                    buffer.edit(edits, None, cx);
 4589                })
 4590            }
 4591            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4592            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4593            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4594            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4595                new_anchor_selections,
 4596                &map,
 4597            )
 4598            .zip(new_selection_deltas)
 4599            .map(|(selection, delta)| Selection {
 4600                id: selection.id,
 4601                start: selection.start + delta,
 4602                end: selection.end + delta,
 4603                reversed: selection.reversed,
 4604                goal: SelectionGoal::None,
 4605            })
 4606            .collect::<Vec<_>>();
 4607
 4608            let mut i = 0;
 4609            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4610                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4611                let start = map.buffer_snapshot().anchor_before(position);
 4612                let end = map.buffer_snapshot().anchor_after(position);
 4613                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4614                    match existing_state
 4615                        .range
 4616                        .start
 4617                        .cmp(&start, map.buffer_snapshot())
 4618                    {
 4619                        Ordering::Less => i += 1,
 4620                        Ordering::Greater => break,
 4621                        Ordering::Equal => {
 4622                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4623                                Ordering::Less => i += 1,
 4624                                Ordering::Equal => break,
 4625                                Ordering::Greater => break,
 4626                            }
 4627                        }
 4628                    }
 4629                }
 4630                this.autoclose_regions.insert(
 4631                    i,
 4632                    AutocloseRegion {
 4633                        selection_id,
 4634                        range: start..end,
 4635                        pair,
 4636                    },
 4637                );
 4638            }
 4639
 4640            let had_active_edit_prediction = this.has_active_edit_prediction();
 4641            this.change_selections(
 4642                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4643                window,
 4644                cx,
 4645                |s| s.select(new_selections),
 4646            );
 4647
 4648            if !bracket_inserted
 4649                && let Some(on_type_format_task) =
 4650                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4651            {
 4652                on_type_format_task.detach_and_log_err(cx);
 4653            }
 4654
 4655            let editor_settings = EditorSettings::get_global(cx);
 4656            if bracket_inserted
 4657                && (editor_settings.auto_signature_help
 4658                    || editor_settings.show_signature_help_after_edits)
 4659            {
 4660                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4661            }
 4662
 4663            let trigger_in_words =
 4664                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4665            if this.hard_wrap.is_some() {
 4666                let latest: Range<Point> = this.selections.newest(&map).range();
 4667                if latest.is_empty()
 4668                    && this
 4669                        .buffer()
 4670                        .read(cx)
 4671                        .snapshot(cx)
 4672                        .line_len(MultiBufferRow(latest.start.row))
 4673                        == latest.start.column
 4674                {
 4675                    this.rewrap_impl(
 4676                        RewrapOptions {
 4677                            override_language_settings: true,
 4678                            preserve_existing_whitespace: true,
 4679                        },
 4680                        cx,
 4681                    )
 4682                }
 4683            }
 4684            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4685            refresh_linked_ranges(this, window, cx);
 4686            this.refresh_edit_prediction(true, false, window, cx);
 4687            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4688        });
 4689    }
 4690
 4691    fn find_possible_emoji_shortcode_at_position(
 4692        snapshot: &MultiBufferSnapshot,
 4693        position: Point,
 4694    ) -> Option<String> {
 4695        let mut chars = Vec::new();
 4696        let mut found_colon = false;
 4697        for char in snapshot.reversed_chars_at(position).take(100) {
 4698            // Found a possible emoji shortcode in the middle of the buffer
 4699            if found_colon {
 4700                if char.is_whitespace() {
 4701                    chars.reverse();
 4702                    return Some(chars.iter().collect());
 4703                }
 4704                // If the previous character is not a whitespace, we are in the middle of a word
 4705                // and we only want to complete the shortcode if the word is made up of other emojis
 4706                let mut containing_word = String::new();
 4707                for ch in snapshot
 4708                    .reversed_chars_at(position)
 4709                    .skip(chars.len() + 1)
 4710                    .take(100)
 4711                {
 4712                    if ch.is_whitespace() {
 4713                        break;
 4714                    }
 4715                    containing_word.push(ch);
 4716                }
 4717                let containing_word = containing_word.chars().rev().collect::<String>();
 4718                if util::word_consists_of_emojis(containing_word.as_str()) {
 4719                    chars.reverse();
 4720                    return Some(chars.iter().collect());
 4721                }
 4722            }
 4723
 4724            if char.is_whitespace() || !char.is_ascii() {
 4725                return None;
 4726            }
 4727            if char == ':' {
 4728                found_colon = true;
 4729            } else {
 4730                chars.push(char);
 4731            }
 4732        }
 4733        // Found a possible emoji shortcode at the beginning of the buffer
 4734        chars.reverse();
 4735        Some(chars.iter().collect())
 4736    }
 4737
 4738    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4739        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4740        self.transact(window, cx, |this, window, cx| {
 4741            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4742                let selections = this
 4743                    .selections
 4744                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4745                let multi_buffer = this.buffer.read(cx);
 4746                let buffer = multi_buffer.snapshot(cx);
 4747                selections
 4748                    .iter()
 4749                    .map(|selection| {
 4750                        let start_point = selection.start.to_point(&buffer);
 4751                        let mut existing_indent =
 4752                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4753                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4754                        let start = selection.start;
 4755                        let end = selection.end;
 4756                        let selection_is_empty = start == end;
 4757                        let language_scope = buffer.language_scope_at(start);
 4758                        let (
 4759                            comment_delimiter,
 4760                            doc_delimiter,
 4761                            insert_extra_newline,
 4762                            indent_on_newline,
 4763                            indent_on_extra_newline,
 4764                        ) = if let Some(language) = &language_scope {
 4765                            let mut insert_extra_newline =
 4766                                insert_extra_newline_brackets(&buffer, start..end, language)
 4767                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4768
 4769                            // Comment extension on newline is allowed only for cursor selections
 4770                            let comment_delimiter = maybe!({
 4771                                if !selection_is_empty {
 4772                                    return None;
 4773                                }
 4774
 4775                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4776                                    return None;
 4777                                }
 4778
 4779                                let delimiters = language.line_comment_prefixes();
 4780                                let max_len_of_delimiter =
 4781                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4782                                let (snapshot, range) =
 4783                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4784
 4785                                let num_of_whitespaces = snapshot
 4786                                    .chars_for_range(range.clone())
 4787                                    .take_while(|c| c.is_whitespace())
 4788                                    .count();
 4789                                let comment_candidate = snapshot
 4790                                    .chars_for_range(range.clone())
 4791                                    .skip(num_of_whitespaces)
 4792                                    .take(max_len_of_delimiter)
 4793                                    .collect::<String>();
 4794                                let (delimiter, trimmed_len) = delimiters
 4795                                    .iter()
 4796                                    .filter_map(|delimiter| {
 4797                                        let prefix = delimiter.trim_end();
 4798                                        if comment_candidate.starts_with(prefix) {
 4799                                            Some((delimiter, prefix.len()))
 4800                                        } else {
 4801                                            None
 4802                                        }
 4803                                    })
 4804                                    .max_by_key(|(_, len)| *len)?;
 4805
 4806                                if let Some(BlockCommentConfig {
 4807                                    start: block_start, ..
 4808                                }) = language.block_comment()
 4809                                {
 4810                                    let block_start_trimmed = block_start.trim_end();
 4811                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4812                                        let line_content = snapshot
 4813                                            .chars_for_range(range)
 4814                                            .skip(num_of_whitespaces)
 4815                                            .take(block_start_trimmed.len())
 4816                                            .collect::<String>();
 4817
 4818                                        if line_content.starts_with(block_start_trimmed) {
 4819                                            return None;
 4820                                        }
 4821                                    }
 4822                                }
 4823
 4824                                let cursor_is_placed_after_comment_marker =
 4825                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4826                                if cursor_is_placed_after_comment_marker {
 4827                                    Some(delimiter.clone())
 4828                                } else {
 4829                                    None
 4830                                }
 4831                            });
 4832
 4833                            let mut indent_on_newline = IndentSize::spaces(0);
 4834                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4835
 4836                            let doc_delimiter = maybe!({
 4837                                if !selection_is_empty {
 4838                                    return None;
 4839                                }
 4840
 4841                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4842                                    return None;
 4843                                }
 4844
 4845                                let BlockCommentConfig {
 4846                                    start: start_tag,
 4847                                    end: end_tag,
 4848                                    prefix: delimiter,
 4849                                    tab_size: len,
 4850                                } = language.documentation_comment()?;
 4851                                let is_within_block_comment = buffer
 4852                                    .language_scope_at(start_point)
 4853                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4854                                if !is_within_block_comment {
 4855                                    return None;
 4856                                }
 4857
 4858                                let (snapshot, range) =
 4859                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4860
 4861                                let num_of_whitespaces = snapshot
 4862                                    .chars_for_range(range.clone())
 4863                                    .take_while(|c| c.is_whitespace())
 4864                                    .count();
 4865
 4866                                // 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.
 4867                                let column = start_point.column;
 4868                                let cursor_is_after_start_tag = {
 4869                                    let start_tag_len = start_tag.len();
 4870                                    let start_tag_line = snapshot
 4871                                        .chars_for_range(range.clone())
 4872                                        .skip(num_of_whitespaces)
 4873                                        .take(start_tag_len)
 4874                                        .collect::<String>();
 4875                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4876                                        num_of_whitespaces + start_tag_len <= column as usize
 4877                                    } else {
 4878                                        false
 4879                                    }
 4880                                };
 4881
 4882                                let cursor_is_after_delimiter = {
 4883                                    let delimiter_trim = delimiter.trim_end();
 4884                                    let delimiter_line = snapshot
 4885                                        .chars_for_range(range.clone())
 4886                                        .skip(num_of_whitespaces)
 4887                                        .take(delimiter_trim.len())
 4888                                        .collect::<String>();
 4889                                    if delimiter_line.starts_with(delimiter_trim) {
 4890                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4891                                    } else {
 4892                                        false
 4893                                    }
 4894                                };
 4895
 4896                                let cursor_is_before_end_tag_if_exists = {
 4897                                    let mut char_position = 0u32;
 4898                                    let mut end_tag_offset = None;
 4899
 4900                                    'outer: for chunk in snapshot.text_for_range(range) {
 4901                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4902                                            let chars_before_match =
 4903                                                chunk[..byte_pos].chars().count() as u32;
 4904                                            end_tag_offset =
 4905                                                Some(char_position + chars_before_match);
 4906                                            break 'outer;
 4907                                        }
 4908                                        char_position += chunk.chars().count() as u32;
 4909                                    }
 4910
 4911                                    if let Some(end_tag_offset) = end_tag_offset {
 4912                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4913                                        if cursor_is_after_start_tag {
 4914                                            if cursor_is_before_end_tag {
 4915                                                insert_extra_newline = true;
 4916                                            }
 4917                                            let cursor_is_at_start_of_end_tag =
 4918                                                column == end_tag_offset;
 4919                                            if cursor_is_at_start_of_end_tag {
 4920                                                indent_on_extra_newline.len = *len;
 4921                                            }
 4922                                        }
 4923                                        cursor_is_before_end_tag
 4924                                    } else {
 4925                                        true
 4926                                    }
 4927                                };
 4928
 4929                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4930                                    && cursor_is_before_end_tag_if_exists
 4931                                {
 4932                                    if cursor_is_after_start_tag {
 4933                                        indent_on_newline.len = *len;
 4934                                    }
 4935                                    Some(delimiter.clone())
 4936                                } else {
 4937                                    None
 4938                                }
 4939                            });
 4940
 4941                            (
 4942                                comment_delimiter,
 4943                                doc_delimiter,
 4944                                insert_extra_newline,
 4945                                indent_on_newline,
 4946                                indent_on_extra_newline,
 4947                            )
 4948                        } else {
 4949                            (
 4950                                None,
 4951                                None,
 4952                                false,
 4953                                IndentSize::default(),
 4954                                IndentSize::default(),
 4955                            )
 4956                        };
 4957
 4958                        let prevent_auto_indent = doc_delimiter.is_some();
 4959                        let delimiter = comment_delimiter.or(doc_delimiter);
 4960
 4961                        let capacity_for_delimiter =
 4962                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4963                        let mut new_text = String::with_capacity(
 4964                            1 + capacity_for_delimiter
 4965                                + existing_indent.len as usize
 4966                                + indent_on_newline.len as usize
 4967                                + indent_on_extra_newline.len as usize,
 4968                        );
 4969                        new_text.push('\n');
 4970                        new_text.extend(existing_indent.chars());
 4971                        new_text.extend(indent_on_newline.chars());
 4972
 4973                        if let Some(delimiter) = &delimiter {
 4974                            new_text.push_str(delimiter);
 4975                        }
 4976
 4977                        if insert_extra_newline {
 4978                            new_text.push('\n');
 4979                            new_text.extend(existing_indent.chars());
 4980                            new_text.extend(indent_on_extra_newline.chars());
 4981                        }
 4982
 4983                        let anchor = buffer.anchor_after(end);
 4984                        let new_selection = selection.map(|_| anchor);
 4985                        (
 4986                            ((start..end, new_text), prevent_auto_indent),
 4987                            (insert_extra_newline, new_selection),
 4988                        )
 4989                    })
 4990                    .unzip()
 4991            };
 4992
 4993            let mut auto_indent_edits = Vec::new();
 4994            let mut edits = Vec::new();
 4995            for (edit, prevent_auto_indent) in edits_with_flags {
 4996                if prevent_auto_indent {
 4997                    edits.push(edit);
 4998                } else {
 4999                    auto_indent_edits.push(edit);
 5000                }
 5001            }
 5002            if !edits.is_empty() {
 5003                this.edit(edits, cx);
 5004            }
 5005            if !auto_indent_edits.is_empty() {
 5006                this.edit_with_autoindent(auto_indent_edits, cx);
 5007            }
 5008
 5009            let buffer = this.buffer.read(cx).snapshot(cx);
 5010            let new_selections = selection_info
 5011                .into_iter()
 5012                .map(|(extra_newline_inserted, new_selection)| {
 5013                    let mut cursor = new_selection.end.to_point(&buffer);
 5014                    if extra_newline_inserted {
 5015                        cursor.row -= 1;
 5016                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5017                    }
 5018                    new_selection.map(|_| cursor)
 5019                })
 5020                .collect();
 5021
 5022            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5023            this.refresh_edit_prediction(true, false, window, cx);
 5024            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5025                task.detach_and_log_err(cx);
 5026            }
 5027        });
 5028    }
 5029
 5030    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5031        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5032
 5033        let buffer = self.buffer.read(cx);
 5034        let snapshot = buffer.snapshot(cx);
 5035
 5036        let mut edits = Vec::new();
 5037        let mut rows = Vec::new();
 5038
 5039        for (rows_inserted, selection) in self
 5040            .selections
 5041            .all_adjusted(&self.display_snapshot(cx))
 5042            .into_iter()
 5043            .enumerate()
 5044        {
 5045            let cursor = selection.head();
 5046            let row = cursor.row;
 5047
 5048            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5049
 5050            let newline = "\n".to_string();
 5051            edits.push((start_of_line..start_of_line, newline));
 5052
 5053            rows.push(row + rows_inserted as u32);
 5054        }
 5055
 5056        self.transact(window, cx, |editor, window, cx| {
 5057            editor.edit(edits, cx);
 5058
 5059            editor.change_selections(Default::default(), window, cx, |s| {
 5060                let mut index = 0;
 5061                s.move_cursors_with(|map, _, _| {
 5062                    let row = rows[index];
 5063                    index += 1;
 5064
 5065                    let point = Point::new(row, 0);
 5066                    let boundary = map.next_line_boundary(point).1;
 5067                    let clipped = map.clip_point(boundary, Bias::Left);
 5068
 5069                    (clipped, SelectionGoal::None)
 5070                });
 5071            });
 5072
 5073            let mut indent_edits = Vec::new();
 5074            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5075            for row in rows {
 5076                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5077                for (row, indent) in indents {
 5078                    if indent.len == 0 {
 5079                        continue;
 5080                    }
 5081
 5082                    let text = match indent.kind {
 5083                        IndentKind::Space => " ".repeat(indent.len as usize),
 5084                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5085                    };
 5086                    let point = Point::new(row.0, 0);
 5087                    indent_edits.push((point..point, text));
 5088                }
 5089            }
 5090            editor.edit(indent_edits, cx);
 5091            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5092                format.detach_and_log_err(cx);
 5093            }
 5094        });
 5095    }
 5096
 5097    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5098        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5099
 5100        let buffer = self.buffer.read(cx);
 5101        let snapshot = buffer.snapshot(cx);
 5102
 5103        let mut edits = Vec::new();
 5104        let mut rows = Vec::new();
 5105        let mut rows_inserted = 0;
 5106
 5107        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5108            let cursor = selection.head();
 5109            let row = cursor.row;
 5110
 5111            let point = Point::new(row + 1, 0);
 5112            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5113
 5114            let newline = "\n".to_string();
 5115            edits.push((start_of_line..start_of_line, newline));
 5116
 5117            rows_inserted += 1;
 5118            rows.push(row + rows_inserted);
 5119        }
 5120
 5121        self.transact(window, cx, |editor, window, cx| {
 5122            editor.edit(edits, cx);
 5123
 5124            editor.change_selections(Default::default(), window, cx, |s| {
 5125                let mut index = 0;
 5126                s.move_cursors_with(|map, _, _| {
 5127                    let row = rows[index];
 5128                    index += 1;
 5129
 5130                    let point = Point::new(row, 0);
 5131                    let boundary = map.next_line_boundary(point).1;
 5132                    let clipped = map.clip_point(boundary, Bias::Left);
 5133
 5134                    (clipped, SelectionGoal::None)
 5135                });
 5136            });
 5137
 5138            let mut indent_edits = Vec::new();
 5139            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5140            for row in rows {
 5141                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5142                for (row, indent) in indents {
 5143                    if indent.len == 0 {
 5144                        continue;
 5145                    }
 5146
 5147                    let text = match indent.kind {
 5148                        IndentKind::Space => " ".repeat(indent.len as usize),
 5149                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5150                    };
 5151                    let point = Point::new(row.0, 0);
 5152                    indent_edits.push((point..point, text));
 5153                }
 5154            }
 5155            editor.edit(indent_edits, cx);
 5156            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5157                format.detach_and_log_err(cx);
 5158            }
 5159        });
 5160    }
 5161
 5162    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5163        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5164            original_indent_columns: Vec::new(),
 5165        });
 5166        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5167    }
 5168
 5169    fn insert_with_autoindent_mode(
 5170        &mut self,
 5171        text: &str,
 5172        autoindent_mode: Option<AutoindentMode>,
 5173        window: &mut Window,
 5174        cx: &mut Context<Self>,
 5175    ) {
 5176        if self.read_only(cx) {
 5177            return;
 5178        }
 5179
 5180        let text: Arc<str> = text.into();
 5181        self.transact(window, cx, |this, window, cx| {
 5182            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5183            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5184                let anchors = {
 5185                    let snapshot = buffer.read(cx);
 5186                    old_selections
 5187                        .iter()
 5188                        .map(|s| {
 5189                            let anchor = snapshot.anchor_after(s.head());
 5190                            s.map(|_| anchor)
 5191                        })
 5192                        .collect::<Vec<_>>()
 5193                };
 5194                buffer.edit(
 5195                    old_selections
 5196                        .iter()
 5197                        .map(|s| (s.start..s.end, text.clone())),
 5198                    autoindent_mode,
 5199                    cx,
 5200                );
 5201                anchors
 5202            });
 5203
 5204            this.change_selections(Default::default(), window, cx, |s| {
 5205                s.select_anchors(selection_anchors);
 5206            });
 5207
 5208            cx.notify();
 5209        });
 5210    }
 5211
 5212    fn trigger_completion_on_input(
 5213        &mut self,
 5214        text: &str,
 5215        trigger_in_words: bool,
 5216        window: &mut Window,
 5217        cx: &mut Context<Self>,
 5218    ) {
 5219        let completions_source = self
 5220            .context_menu
 5221            .borrow()
 5222            .as_ref()
 5223            .and_then(|menu| match menu {
 5224                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5225                CodeContextMenu::CodeActions(_) => None,
 5226            });
 5227
 5228        match completions_source {
 5229            Some(CompletionsMenuSource::Words { .. }) => {
 5230                self.open_or_update_completions_menu(
 5231                    Some(CompletionsMenuSource::Words {
 5232                        ignore_threshold: false,
 5233                    }),
 5234                    None,
 5235                    trigger_in_words,
 5236                    window,
 5237                    cx,
 5238                );
 5239            }
 5240            _ => self.open_or_update_completions_menu(
 5241                None,
 5242                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5243                true,
 5244                window,
 5245                cx,
 5246            ),
 5247        }
 5248    }
 5249
 5250    /// If any empty selections is touching the start of its innermost containing autoclose
 5251    /// region, expand it to select the brackets.
 5252    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5253        let selections = self
 5254            .selections
 5255            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5256        let buffer = self.buffer.read(cx).read(cx);
 5257        let new_selections = self
 5258            .selections_with_autoclose_regions(selections, &buffer)
 5259            .map(|(mut selection, region)| {
 5260                if !selection.is_empty() {
 5261                    return selection;
 5262                }
 5263
 5264                if let Some(region) = region {
 5265                    let mut range = region.range.to_offset(&buffer);
 5266                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5267                        range.start -= region.pair.start.len();
 5268                        if buffer.contains_str_at(range.start, &region.pair.start)
 5269                            && buffer.contains_str_at(range.end, &region.pair.end)
 5270                        {
 5271                            range.end += region.pair.end.len();
 5272                            selection.start = range.start;
 5273                            selection.end = range.end;
 5274
 5275                            return selection;
 5276                        }
 5277                    }
 5278                }
 5279
 5280                let always_treat_brackets_as_autoclosed = buffer
 5281                    .language_settings_at(selection.start, cx)
 5282                    .always_treat_brackets_as_autoclosed;
 5283
 5284                if !always_treat_brackets_as_autoclosed {
 5285                    return selection;
 5286                }
 5287
 5288                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5289                    for (pair, enabled) in scope.brackets() {
 5290                        if !enabled || !pair.close {
 5291                            continue;
 5292                        }
 5293
 5294                        if buffer.contains_str_at(selection.start, &pair.end) {
 5295                            let pair_start_len = pair.start.len();
 5296                            if buffer.contains_str_at(
 5297                                selection.start.saturating_sub_usize(pair_start_len),
 5298                                &pair.start,
 5299                            ) {
 5300                                selection.start -= pair_start_len;
 5301                                selection.end += pair.end.len();
 5302
 5303                                return selection;
 5304                            }
 5305                        }
 5306                    }
 5307                }
 5308
 5309                selection
 5310            })
 5311            .collect();
 5312
 5313        drop(buffer);
 5314        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5315            selections.select(new_selections)
 5316        });
 5317    }
 5318
 5319    /// Iterate the given selections, and for each one, find the smallest surrounding
 5320    /// autoclose region. This uses the ordering of the selections and the autoclose
 5321    /// regions to avoid repeated comparisons.
 5322    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5323        &'a self,
 5324        selections: impl IntoIterator<Item = Selection<D>>,
 5325        buffer: &'a MultiBufferSnapshot,
 5326    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5327        let mut i = 0;
 5328        let mut regions = self.autoclose_regions.as_slice();
 5329        selections.into_iter().map(move |selection| {
 5330            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5331
 5332            let mut enclosing = None;
 5333            while let Some(pair_state) = regions.get(i) {
 5334                if pair_state.range.end.to_offset(buffer) < range.start {
 5335                    regions = &regions[i + 1..];
 5336                    i = 0;
 5337                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5338                    break;
 5339                } else {
 5340                    if pair_state.selection_id == selection.id {
 5341                        enclosing = Some(pair_state);
 5342                    }
 5343                    i += 1;
 5344                }
 5345            }
 5346
 5347            (selection, enclosing)
 5348        })
 5349    }
 5350
 5351    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5352    fn invalidate_autoclose_regions(
 5353        &mut self,
 5354        mut selections: &[Selection<Anchor>],
 5355        buffer: &MultiBufferSnapshot,
 5356    ) {
 5357        self.autoclose_regions.retain(|state| {
 5358            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5359                return false;
 5360            }
 5361
 5362            let mut i = 0;
 5363            while let Some(selection) = selections.get(i) {
 5364                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5365                    selections = &selections[1..];
 5366                    continue;
 5367                }
 5368                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5369                    break;
 5370                }
 5371                if selection.id == state.selection_id {
 5372                    return true;
 5373                } else {
 5374                    i += 1;
 5375                }
 5376            }
 5377            false
 5378        });
 5379    }
 5380
 5381    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5382        let offset = position.to_offset(buffer);
 5383        let (word_range, kind) =
 5384            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5385        if offset > word_range.start && kind == Some(CharKind::Word) {
 5386            Some(
 5387                buffer
 5388                    .text_for_range(word_range.start..offset)
 5389                    .collect::<String>(),
 5390            )
 5391        } else {
 5392            None
 5393        }
 5394    }
 5395
 5396    pub fn visible_excerpts(
 5397        &self,
 5398        lsp_related_only: bool,
 5399        cx: &mut Context<Editor>,
 5400    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5401        let project = self.project().cloned();
 5402        let multi_buffer = self.buffer().read(cx);
 5403        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5404        let multi_buffer_visible_start = self
 5405            .scroll_manager
 5406            .anchor()
 5407            .anchor
 5408            .to_point(&multi_buffer_snapshot);
 5409        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5410            multi_buffer_visible_start
 5411                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5412            Bias::Left,
 5413        );
 5414        multi_buffer_snapshot
 5415            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5416            .into_iter()
 5417            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5418            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5419                if !lsp_related_only {
 5420                    return Some((
 5421                        excerpt_id,
 5422                        (
 5423                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5424                            buffer.version().clone(),
 5425                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5426                        ),
 5427                    ));
 5428                }
 5429
 5430                let project = project.as_ref()?.read(cx);
 5431                let buffer_file = project::File::from_dyn(buffer.file())?;
 5432                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5433                let worktree_entry = buffer_worktree
 5434                    .read(cx)
 5435                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5436                if worktree_entry.is_ignored {
 5437                    None
 5438                } else {
 5439                    Some((
 5440                        excerpt_id,
 5441                        (
 5442                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5443                            buffer.version().clone(),
 5444                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5445                        ),
 5446                    ))
 5447                }
 5448            })
 5449            .collect()
 5450    }
 5451
 5452    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5453        TextLayoutDetails {
 5454            text_system: window.text_system().clone(),
 5455            editor_style: self.style.clone().unwrap(),
 5456            rem_size: window.rem_size(),
 5457            scroll_anchor: self.scroll_manager.anchor(),
 5458            visible_rows: self.visible_line_count(),
 5459            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5460        }
 5461    }
 5462
 5463    fn trigger_on_type_formatting(
 5464        &self,
 5465        input: String,
 5466        window: &mut Window,
 5467        cx: &mut Context<Self>,
 5468    ) -> Option<Task<Result<()>>> {
 5469        if input.chars().count() != 1 {
 5470            return None;
 5471        }
 5472
 5473        let project = self.project()?;
 5474        let position = self.selections.newest_anchor().head();
 5475        let (buffer, buffer_position) = self
 5476            .buffer
 5477            .read(cx)
 5478            .text_anchor_for_position(position, cx)?;
 5479
 5480        let settings = language_settings::language_settings(
 5481            buffer
 5482                .read(cx)
 5483                .language_at(buffer_position)
 5484                .map(|l| l.name()),
 5485            buffer.read(cx).file(),
 5486            cx,
 5487        );
 5488        if !settings.use_on_type_format {
 5489            return None;
 5490        }
 5491
 5492        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5493        // hence we do LSP request & edit on host side only — add formats to host's history.
 5494        let push_to_lsp_host_history = true;
 5495        // If this is not the host, append its history with new edits.
 5496        let push_to_client_history = project.read(cx).is_via_collab();
 5497
 5498        let on_type_formatting = project.update(cx, |project, cx| {
 5499            project.on_type_format(
 5500                buffer.clone(),
 5501                buffer_position,
 5502                input,
 5503                push_to_lsp_host_history,
 5504                cx,
 5505            )
 5506        });
 5507        Some(cx.spawn_in(window, async move |editor, cx| {
 5508            if let Some(transaction) = on_type_formatting.await? {
 5509                if push_to_client_history {
 5510                    buffer
 5511                        .update(cx, |buffer, _| {
 5512                            buffer.push_transaction(transaction, Instant::now());
 5513                            buffer.finalize_last_transaction();
 5514                        })
 5515                        .ok();
 5516                }
 5517                editor.update(cx, |editor, cx| {
 5518                    editor.refresh_document_highlights(cx);
 5519                })?;
 5520            }
 5521            Ok(())
 5522        }))
 5523    }
 5524
 5525    pub fn show_word_completions(
 5526        &mut self,
 5527        _: &ShowWordCompletions,
 5528        window: &mut Window,
 5529        cx: &mut Context<Self>,
 5530    ) {
 5531        self.open_or_update_completions_menu(
 5532            Some(CompletionsMenuSource::Words {
 5533                ignore_threshold: true,
 5534            }),
 5535            None,
 5536            false,
 5537            window,
 5538            cx,
 5539        );
 5540    }
 5541
 5542    pub fn show_completions(
 5543        &mut self,
 5544        _: &ShowCompletions,
 5545        window: &mut Window,
 5546        cx: &mut Context<Self>,
 5547    ) {
 5548        self.open_or_update_completions_menu(None, None, false, window, cx);
 5549    }
 5550
 5551    fn open_or_update_completions_menu(
 5552        &mut self,
 5553        requested_source: Option<CompletionsMenuSource>,
 5554        trigger: Option<String>,
 5555        trigger_in_words: bool,
 5556        window: &mut Window,
 5557        cx: &mut Context<Self>,
 5558    ) {
 5559        if self.pending_rename.is_some() {
 5560            return;
 5561        }
 5562
 5563        let completions_source = self
 5564            .context_menu
 5565            .borrow()
 5566            .as_ref()
 5567            .and_then(|menu| match menu {
 5568                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5569                CodeContextMenu::CodeActions(_) => None,
 5570            });
 5571
 5572        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5573
 5574        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5575        // inserted and selected. To handle that case, the start of the selection is used so that
 5576        // the menu starts with all choices.
 5577        let position = self
 5578            .selections
 5579            .newest_anchor()
 5580            .start
 5581            .bias_right(&multibuffer_snapshot);
 5582        if position.diff_base_anchor.is_some() {
 5583            return;
 5584        }
 5585        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5586        let Some(buffer) = buffer_position
 5587            .text_anchor
 5588            .buffer_id
 5589            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5590        else {
 5591            return;
 5592        };
 5593        let buffer_snapshot = buffer.read(cx).snapshot();
 5594
 5595        let menu_is_open = matches!(
 5596            self.context_menu.borrow().as_ref(),
 5597            Some(CodeContextMenu::Completions(_))
 5598        );
 5599
 5600        let language = buffer_snapshot
 5601            .language_at(buffer_position.text_anchor)
 5602            .map(|language| language.name());
 5603
 5604        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5605        let completion_settings = language_settings.completions.clone();
 5606
 5607        let show_completions_on_input = self
 5608            .show_completions_on_input_override
 5609            .unwrap_or(language_settings.show_completions_on_input);
 5610        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5611            return;
 5612        }
 5613
 5614        let query: Option<Arc<String>> =
 5615            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5616                .map(|query| query.into());
 5617
 5618        drop(multibuffer_snapshot);
 5619
 5620        // Hide the current completions menu when query is empty. Without this, cached
 5621        // completions from before the trigger char may be reused (#32774).
 5622        if query.is_none() && menu_is_open {
 5623            self.hide_context_menu(window, cx);
 5624        }
 5625
 5626        let mut ignore_word_threshold = false;
 5627        let provider = match requested_source {
 5628            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5629            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5630                ignore_word_threshold = ignore_threshold;
 5631                None
 5632            }
 5633            Some(CompletionsMenuSource::SnippetChoices)
 5634            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5635                log::error!("bug: SnippetChoices requested_source is not handled");
 5636                None
 5637            }
 5638        };
 5639
 5640        let sort_completions = provider
 5641            .as_ref()
 5642            .is_some_and(|provider| provider.sort_completions());
 5643
 5644        let filter_completions = provider
 5645            .as_ref()
 5646            .is_none_or(|provider| provider.filter_completions());
 5647
 5648        let was_snippets_only = matches!(
 5649            completions_source,
 5650            Some(CompletionsMenuSource::SnippetsOnly)
 5651        );
 5652
 5653        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5654            if filter_completions {
 5655                menu.filter(
 5656                    query.clone().unwrap_or_default(),
 5657                    buffer_position.text_anchor,
 5658                    &buffer,
 5659                    provider.clone(),
 5660                    window,
 5661                    cx,
 5662                );
 5663            }
 5664            // When `is_incomplete` is false, no need to re-query completions when the current query
 5665            // is a suffix of the initial query.
 5666            let was_complete = !menu.is_incomplete;
 5667            if was_complete && !was_snippets_only {
 5668                // If the new query is a suffix of the old query (typing more characters) and
 5669                // the previous result was complete, the existing completions can be filtered.
 5670                //
 5671                // Note that snippet completions are always complete.
 5672                let query_matches = match (&menu.initial_query, &query) {
 5673                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5674                    (None, _) => true,
 5675                    _ => false,
 5676                };
 5677                if query_matches {
 5678                    let position_matches = if menu.initial_position == position {
 5679                        true
 5680                    } else {
 5681                        let snapshot = self.buffer.read(cx).read(cx);
 5682                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5683                    };
 5684                    if position_matches {
 5685                        return;
 5686                    }
 5687                }
 5688            }
 5689        };
 5690
 5691        let Anchor {
 5692            excerpt_id: buffer_excerpt_id,
 5693            text_anchor: buffer_position,
 5694            ..
 5695        } = buffer_position;
 5696
 5697        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5698            buffer_snapshot.surrounding_word(buffer_position, None)
 5699        {
 5700            let word_to_exclude = buffer_snapshot
 5701                .text_for_range(word_range.clone())
 5702                .collect::<String>();
 5703            (
 5704                buffer_snapshot.anchor_before(word_range.start)
 5705                    ..buffer_snapshot.anchor_after(buffer_position),
 5706                Some(word_to_exclude),
 5707            )
 5708        } else {
 5709            (buffer_position..buffer_position, None)
 5710        };
 5711
 5712        let show_completion_documentation = buffer_snapshot
 5713            .settings_at(buffer_position, cx)
 5714            .show_completion_documentation;
 5715
 5716        // The document can be large, so stay in reasonable bounds when searching for words,
 5717        // otherwise completion pop-up might be slow to appear.
 5718        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5719        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5720        let min_word_search = buffer_snapshot.clip_point(
 5721            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5722            Bias::Left,
 5723        );
 5724        let max_word_search = buffer_snapshot.clip_point(
 5725            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5726            Bias::Right,
 5727        );
 5728        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5729            ..buffer_snapshot.point_to_offset(max_word_search);
 5730
 5731        let skip_digits = query
 5732            .as_ref()
 5733            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5734
 5735        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5736            trigger.as_ref().is_none_or(|trigger| {
 5737                provider.is_completion_trigger(
 5738                    &buffer,
 5739                    position.text_anchor,
 5740                    trigger,
 5741                    trigger_in_words,
 5742                    cx,
 5743                )
 5744            })
 5745        });
 5746
 5747        let provider_responses = if let Some(provider) = &provider
 5748            && load_provider_completions
 5749        {
 5750            let trigger_character =
 5751                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5752            let completion_context = CompletionContext {
 5753                trigger_kind: match &trigger_character {
 5754                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5755                    None => CompletionTriggerKind::INVOKED,
 5756                },
 5757                trigger_character,
 5758            };
 5759
 5760            provider.completions(
 5761                buffer_excerpt_id,
 5762                &buffer,
 5763                buffer_position,
 5764                completion_context,
 5765                window,
 5766                cx,
 5767            )
 5768        } else {
 5769            Task::ready(Ok(Vec::new()))
 5770        };
 5771
 5772        let load_word_completions = if !self.word_completions_enabled {
 5773            false
 5774        } else if requested_source
 5775            == Some(CompletionsMenuSource::Words {
 5776                ignore_threshold: true,
 5777            })
 5778        {
 5779            true
 5780        } else {
 5781            load_provider_completions
 5782                && completion_settings.words != WordsCompletionMode::Disabled
 5783                && (ignore_word_threshold || {
 5784                    let words_min_length = completion_settings.words_min_length;
 5785                    // check whether word has at least `words_min_length` characters
 5786                    let query_chars = query.iter().flat_map(|q| q.chars());
 5787                    query_chars.take(words_min_length).count() == words_min_length
 5788                })
 5789        };
 5790
 5791        let mut words = if load_word_completions {
 5792            cx.background_spawn({
 5793                let buffer_snapshot = buffer_snapshot.clone();
 5794                async move {
 5795                    buffer_snapshot.words_in_range(WordsQuery {
 5796                        fuzzy_contents: None,
 5797                        range: word_search_range,
 5798                        skip_digits,
 5799                    })
 5800                }
 5801            })
 5802        } else {
 5803            Task::ready(BTreeMap::default())
 5804        };
 5805
 5806        let snippets = if let Some(provider) = &provider
 5807            && provider.show_snippets()
 5808            && let Some(project) = self.project()
 5809        {
 5810            let char_classifier = buffer_snapshot
 5811                .char_classifier_at(buffer_position)
 5812                .scope_context(Some(CharScopeContext::Completion));
 5813            project.update(cx, |project, cx| {
 5814                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5815            })
 5816        } else {
 5817            Task::ready(Ok(CompletionResponse {
 5818                completions: Vec::new(),
 5819                display_options: Default::default(),
 5820                is_incomplete: false,
 5821            }))
 5822        };
 5823
 5824        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5825
 5826        let id = post_inc(&mut self.next_completion_id);
 5827        let task = cx.spawn_in(window, async move |editor, cx| {
 5828            let Ok(()) = editor.update(cx, |this, _| {
 5829                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5830            }) else {
 5831                return;
 5832            };
 5833
 5834            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5835            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5836            let mut completions = Vec::new();
 5837            let mut is_incomplete = false;
 5838            let mut display_options: Option<CompletionDisplayOptions> = None;
 5839            if let Some(provider_responses) = provider_responses.await.log_err()
 5840                && !provider_responses.is_empty()
 5841            {
 5842                for response in provider_responses {
 5843                    completions.extend(response.completions);
 5844                    is_incomplete = is_incomplete || response.is_incomplete;
 5845                    match display_options.as_mut() {
 5846                        None => {
 5847                            display_options = Some(response.display_options);
 5848                        }
 5849                        Some(options) => options.merge(&response.display_options),
 5850                    }
 5851                }
 5852                if completion_settings.words == WordsCompletionMode::Fallback {
 5853                    words = Task::ready(BTreeMap::default());
 5854                }
 5855            }
 5856            let display_options = display_options.unwrap_or_default();
 5857
 5858            let mut words = words.await;
 5859            if let Some(word_to_exclude) = &word_to_exclude {
 5860                words.remove(word_to_exclude);
 5861            }
 5862            for lsp_completion in &completions {
 5863                words.remove(&lsp_completion.new_text);
 5864            }
 5865            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5866                replace_range: word_replace_range.clone(),
 5867                new_text: word.clone(),
 5868                label: CodeLabel::plain(word, None),
 5869                match_start: None,
 5870                snippet_deduplication_key: None,
 5871                icon_path: None,
 5872                documentation: None,
 5873                source: CompletionSource::BufferWord {
 5874                    word_range,
 5875                    resolved: false,
 5876                },
 5877                insert_text_mode: Some(InsertTextMode::AS_IS),
 5878                confirm: None,
 5879            }));
 5880
 5881            completions.extend(
 5882                snippets
 5883                    .await
 5884                    .into_iter()
 5885                    .flat_map(|response| response.completions),
 5886            );
 5887
 5888            let menu = if completions.is_empty() {
 5889                None
 5890            } else {
 5891                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5892                    let languages = editor
 5893                        .workspace
 5894                        .as_ref()
 5895                        .and_then(|(workspace, _)| workspace.upgrade())
 5896                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5897                    let menu = CompletionsMenu::new(
 5898                        id,
 5899                        requested_source.unwrap_or(if load_provider_completions {
 5900                            CompletionsMenuSource::Normal
 5901                        } else {
 5902                            CompletionsMenuSource::SnippetsOnly
 5903                        }),
 5904                        sort_completions,
 5905                        show_completion_documentation,
 5906                        position,
 5907                        query.clone(),
 5908                        is_incomplete,
 5909                        buffer.clone(),
 5910                        completions.into(),
 5911                        editor
 5912                            .context_menu()
 5913                            .borrow_mut()
 5914                            .as_ref()
 5915                            .map(|menu| menu.primary_scroll_handle()),
 5916                        display_options,
 5917                        snippet_sort_order,
 5918                        languages,
 5919                        language,
 5920                        cx,
 5921                    );
 5922
 5923                    let query = if filter_completions { query } else { None };
 5924                    let matches_task = menu.do_async_filtering(
 5925                        query.unwrap_or_default(),
 5926                        buffer_position,
 5927                        &buffer,
 5928                        cx,
 5929                    );
 5930                    (menu, matches_task)
 5931                }) else {
 5932                    return;
 5933                };
 5934
 5935                let matches = matches_task.await;
 5936
 5937                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5938                    // Newer menu already set, so exit.
 5939                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5940                        editor.context_menu.borrow().as_ref()
 5941                        && prev_menu.id > id
 5942                    {
 5943                        return;
 5944                    };
 5945
 5946                    // Only valid to take prev_menu because either the new menu is immediately set
 5947                    // below, or the menu is hidden.
 5948                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5949                        editor.context_menu.borrow_mut().take()
 5950                    {
 5951                        let position_matches =
 5952                            if prev_menu.initial_position == menu.initial_position {
 5953                                true
 5954                            } else {
 5955                                let snapshot = editor.buffer.read(cx).read(cx);
 5956                                prev_menu.initial_position.to_offset(&snapshot)
 5957                                    == menu.initial_position.to_offset(&snapshot)
 5958                            };
 5959                        if position_matches {
 5960                            // Preserve markdown cache before `set_filter_results` because it will
 5961                            // try to populate the documentation cache.
 5962                            menu.preserve_markdown_cache(prev_menu);
 5963                        }
 5964                    };
 5965
 5966                    menu.set_filter_results(matches, provider, window, cx);
 5967                }) else {
 5968                    return;
 5969                };
 5970
 5971                menu.visible().then_some(menu)
 5972            };
 5973
 5974            editor
 5975                .update_in(cx, |editor, window, cx| {
 5976                    if editor.focus_handle.is_focused(window)
 5977                        && let Some(menu) = menu
 5978                    {
 5979                        *editor.context_menu.borrow_mut() =
 5980                            Some(CodeContextMenu::Completions(menu));
 5981
 5982                        crate::hover_popover::hide_hover(editor, cx);
 5983                        if editor.show_edit_predictions_in_menu() {
 5984                            editor.update_visible_edit_prediction(window, cx);
 5985                        } else {
 5986                            editor.discard_edit_prediction(false, cx);
 5987                        }
 5988
 5989                        cx.notify();
 5990                        return;
 5991                    }
 5992
 5993                    if editor.completion_tasks.len() <= 1 {
 5994                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5995                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5996                        // If it was already hidden and we don't show edit predictions in the menu,
 5997                        // we should also show the edit prediction when available.
 5998                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5999                            editor.update_visible_edit_prediction(window, cx);
 6000                        }
 6001                    }
 6002                })
 6003                .ok();
 6004        });
 6005
 6006        self.completion_tasks.push((id, task));
 6007    }
 6008
 6009    #[cfg(feature = "test-support")]
 6010    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6011        let menu = self.context_menu.borrow();
 6012        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6013            let completions = menu.completions.borrow();
 6014            Some(completions.to_vec())
 6015        } else {
 6016            None
 6017        }
 6018    }
 6019
 6020    pub fn with_completions_menu_matching_id<R>(
 6021        &self,
 6022        id: CompletionId,
 6023        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6024    ) -> R {
 6025        let mut context_menu = self.context_menu.borrow_mut();
 6026        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6027            return f(None);
 6028        };
 6029        if completions_menu.id != id {
 6030            return f(None);
 6031        }
 6032        f(Some(completions_menu))
 6033    }
 6034
 6035    pub fn confirm_completion(
 6036        &mut self,
 6037        action: &ConfirmCompletion,
 6038        window: &mut Window,
 6039        cx: &mut Context<Self>,
 6040    ) -> Option<Task<Result<()>>> {
 6041        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6042        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6043    }
 6044
 6045    pub fn confirm_completion_insert(
 6046        &mut self,
 6047        _: &ConfirmCompletionInsert,
 6048        window: &mut Window,
 6049        cx: &mut Context<Self>,
 6050    ) -> Option<Task<Result<()>>> {
 6051        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6052        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6053    }
 6054
 6055    pub fn confirm_completion_replace(
 6056        &mut self,
 6057        _: &ConfirmCompletionReplace,
 6058        window: &mut Window,
 6059        cx: &mut Context<Self>,
 6060    ) -> Option<Task<Result<()>>> {
 6061        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6062        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6063    }
 6064
 6065    pub fn compose_completion(
 6066        &mut self,
 6067        action: &ComposeCompletion,
 6068        window: &mut Window,
 6069        cx: &mut Context<Self>,
 6070    ) -> Option<Task<Result<()>>> {
 6071        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6072        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6073    }
 6074
 6075    fn do_completion(
 6076        &mut self,
 6077        item_ix: Option<usize>,
 6078        intent: CompletionIntent,
 6079        window: &mut Window,
 6080        cx: &mut Context<Editor>,
 6081    ) -> Option<Task<Result<()>>> {
 6082        use language::ToOffset as _;
 6083
 6084        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6085        else {
 6086            return None;
 6087        };
 6088
 6089        let candidate_id = {
 6090            let entries = completions_menu.entries.borrow();
 6091            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6092            if self.show_edit_predictions_in_menu() {
 6093                self.discard_edit_prediction(true, cx);
 6094            }
 6095            mat.candidate_id
 6096        };
 6097
 6098        let completion = completions_menu
 6099            .completions
 6100            .borrow()
 6101            .get(candidate_id)?
 6102            .clone();
 6103        cx.stop_propagation();
 6104
 6105        let buffer_handle = completions_menu.buffer.clone();
 6106
 6107        let CompletionEdit {
 6108            new_text,
 6109            snippet,
 6110            replace_range,
 6111        } = process_completion_for_edit(
 6112            &completion,
 6113            intent,
 6114            &buffer_handle,
 6115            &completions_menu.initial_position.text_anchor,
 6116            cx,
 6117        );
 6118
 6119        let buffer = buffer_handle.read(cx);
 6120        let snapshot = self.buffer.read(cx).snapshot(cx);
 6121        let newest_anchor = self.selections.newest_anchor();
 6122        let replace_range_multibuffer = {
 6123            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6124            excerpt.map_range_from_buffer(replace_range.clone())
 6125        };
 6126        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6127            return None;
 6128        }
 6129
 6130        let old_text = buffer
 6131            .text_for_range(replace_range.clone())
 6132            .collect::<String>();
 6133        let lookbehind = newest_anchor
 6134            .start
 6135            .text_anchor
 6136            .to_offset(buffer)
 6137            .saturating_sub(replace_range.start.0);
 6138        let lookahead = replace_range
 6139            .end
 6140            .0
 6141            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6142        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6143        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6144
 6145        let selections = self
 6146            .selections
 6147            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6148        let mut ranges = Vec::new();
 6149        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6150
 6151        for selection in &selections {
 6152            let range = if selection.id == newest_anchor.id {
 6153                replace_range_multibuffer.clone()
 6154            } else {
 6155                let mut range = selection.range();
 6156
 6157                // if prefix is present, don't duplicate it
 6158                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6159                    range.start = range.start.saturating_sub_usize(lookbehind);
 6160
 6161                    // if suffix is also present, mimic the newest cursor and replace it
 6162                    if selection.id != newest_anchor.id
 6163                        && snapshot.contains_str_at(range.end, suffix)
 6164                    {
 6165                        range.end += lookahead;
 6166                    }
 6167                }
 6168                range
 6169            };
 6170
 6171            ranges.push(range.clone());
 6172
 6173            if !self.linked_edit_ranges.is_empty() {
 6174                let start_anchor = snapshot.anchor_before(range.start);
 6175                let end_anchor = snapshot.anchor_after(range.end);
 6176                if let Some(ranges) = self
 6177                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6178                {
 6179                    for (buffer, edits) in ranges {
 6180                        linked_edits
 6181                            .entry(buffer.clone())
 6182                            .or_default()
 6183                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6184                    }
 6185                }
 6186            }
 6187        }
 6188
 6189        let common_prefix_len = old_text
 6190            .chars()
 6191            .zip(new_text.chars())
 6192            .take_while(|(a, b)| a == b)
 6193            .map(|(a, _)| a.len_utf8())
 6194            .sum::<usize>();
 6195
 6196        cx.emit(EditorEvent::InputHandled {
 6197            utf16_range_to_replace: None,
 6198            text: new_text[common_prefix_len..].into(),
 6199        });
 6200
 6201        self.transact(window, cx, |editor, window, cx| {
 6202            if let Some(mut snippet) = snippet {
 6203                snippet.text = new_text.to_string();
 6204                editor
 6205                    .insert_snippet(&ranges, snippet, window, cx)
 6206                    .log_err();
 6207            } else {
 6208                editor.buffer.update(cx, |multi_buffer, cx| {
 6209                    let auto_indent = match completion.insert_text_mode {
 6210                        Some(InsertTextMode::AS_IS) => None,
 6211                        _ => editor.autoindent_mode.clone(),
 6212                    };
 6213                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6214                    multi_buffer.edit(edits, auto_indent, cx);
 6215                });
 6216            }
 6217            for (buffer, edits) in linked_edits {
 6218                buffer.update(cx, |buffer, cx| {
 6219                    let snapshot = buffer.snapshot();
 6220                    let edits = edits
 6221                        .into_iter()
 6222                        .map(|(range, text)| {
 6223                            use text::ToPoint as TP;
 6224                            let end_point = TP::to_point(&range.end, &snapshot);
 6225                            let start_point = TP::to_point(&range.start, &snapshot);
 6226                            (start_point..end_point, text)
 6227                        })
 6228                        .sorted_by_key(|(range, _)| range.start);
 6229                    buffer.edit(edits, None, cx);
 6230                })
 6231            }
 6232
 6233            editor.refresh_edit_prediction(true, false, window, cx);
 6234        });
 6235        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6236
 6237        let show_new_completions_on_confirm = completion
 6238            .confirm
 6239            .as_ref()
 6240            .is_some_and(|confirm| confirm(intent, window, cx));
 6241        if show_new_completions_on_confirm {
 6242            self.open_or_update_completions_menu(None, None, false, window, cx);
 6243        }
 6244
 6245        let provider = self.completion_provider.as_ref()?;
 6246
 6247        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6248        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6249            let CompletionSource::Lsp {
 6250                lsp_completion,
 6251                server_id,
 6252                ..
 6253            } = &completion.source
 6254            else {
 6255                return None;
 6256            };
 6257            let lsp_command = lsp_completion.command.as_ref()?;
 6258            let available_commands = lsp_store
 6259                .read(cx)
 6260                .lsp_server_capabilities
 6261                .get(server_id)
 6262                .and_then(|server_capabilities| {
 6263                    server_capabilities
 6264                        .execute_command_provider
 6265                        .as_ref()
 6266                        .map(|options| options.commands.as_slice())
 6267                })?;
 6268            if available_commands.contains(&lsp_command.command) {
 6269                Some(CodeAction {
 6270                    server_id: *server_id,
 6271                    range: language::Anchor::MIN..language::Anchor::MIN,
 6272                    lsp_action: LspAction::Command(lsp_command.clone()),
 6273                    resolved: false,
 6274                })
 6275            } else {
 6276                None
 6277            }
 6278        });
 6279
 6280        drop(completion);
 6281        let apply_edits = provider.apply_additional_edits_for_completion(
 6282            buffer_handle.clone(),
 6283            completions_menu.completions.clone(),
 6284            candidate_id,
 6285            true,
 6286            cx,
 6287        );
 6288
 6289        let editor_settings = EditorSettings::get_global(cx);
 6290        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6291            // After the code completion is finished, users often want to know what signatures are needed.
 6292            // so we should automatically call signature_help
 6293            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6294        }
 6295
 6296        Some(cx.spawn_in(window, async move |editor, cx| {
 6297            apply_edits.await?;
 6298
 6299            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6300                let title = command.lsp_action.title().to_owned();
 6301                let project_transaction = lsp_store
 6302                    .update(cx, |lsp_store, cx| {
 6303                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6304                    })?
 6305                    .await
 6306                    .context("applying post-completion command")?;
 6307                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6308                    Self::open_project_transaction(
 6309                        &editor,
 6310                        workspace.downgrade(),
 6311                        project_transaction,
 6312                        title,
 6313                        cx,
 6314                    )
 6315                    .await?;
 6316                }
 6317            }
 6318
 6319            Ok(())
 6320        }))
 6321    }
 6322
 6323    pub fn toggle_code_actions(
 6324        &mut self,
 6325        action: &ToggleCodeActions,
 6326        window: &mut Window,
 6327        cx: &mut Context<Self>,
 6328    ) {
 6329        let quick_launch = action.quick_launch;
 6330        let mut context_menu = self.context_menu.borrow_mut();
 6331        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6332            if code_actions.deployed_from == action.deployed_from {
 6333                // Toggle if we're selecting the same one
 6334                *context_menu = None;
 6335                cx.notify();
 6336                return;
 6337            } else {
 6338                // Otherwise, clear it and start a new one
 6339                *context_menu = None;
 6340                cx.notify();
 6341            }
 6342        }
 6343        drop(context_menu);
 6344        let snapshot = self.snapshot(window, cx);
 6345        let deployed_from = action.deployed_from.clone();
 6346        let action = action.clone();
 6347        self.completion_tasks.clear();
 6348        self.discard_edit_prediction(false, cx);
 6349
 6350        let multibuffer_point = match &action.deployed_from {
 6351            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6352                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6353            }
 6354            _ => self
 6355                .selections
 6356                .newest::<Point>(&snapshot.display_snapshot)
 6357                .head(),
 6358        };
 6359        let Some((buffer, buffer_row)) = snapshot
 6360            .buffer_snapshot()
 6361            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6362            .and_then(|(buffer_snapshot, range)| {
 6363                self.buffer()
 6364                    .read(cx)
 6365                    .buffer(buffer_snapshot.remote_id())
 6366                    .map(|buffer| (buffer, range.start.row))
 6367            })
 6368        else {
 6369            return;
 6370        };
 6371        let buffer_id = buffer.read(cx).remote_id();
 6372        let tasks = self
 6373            .tasks
 6374            .get(&(buffer_id, buffer_row))
 6375            .map(|t| Arc::new(t.to_owned()));
 6376
 6377        if !self.focus_handle.is_focused(window) {
 6378            return;
 6379        }
 6380        let project = self.project.clone();
 6381
 6382        let code_actions_task = match deployed_from {
 6383            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6384            _ => self.code_actions(buffer_row, window, cx),
 6385        };
 6386
 6387        let runnable_task = match deployed_from {
 6388            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6389            _ => {
 6390                let mut task_context_task = Task::ready(None);
 6391                if let Some(tasks) = &tasks
 6392                    && let Some(project) = project
 6393                {
 6394                    task_context_task =
 6395                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6396                }
 6397
 6398                cx.spawn_in(window, {
 6399                    let buffer = buffer.clone();
 6400                    async move |editor, cx| {
 6401                        let task_context = task_context_task.await;
 6402
 6403                        let resolved_tasks =
 6404                            tasks
 6405                                .zip(task_context.clone())
 6406                                .map(|(tasks, task_context)| ResolvedTasks {
 6407                                    templates: tasks.resolve(&task_context).collect(),
 6408                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6409                                        multibuffer_point.row,
 6410                                        tasks.column,
 6411                                    )),
 6412                                });
 6413                        let debug_scenarios = editor
 6414                            .update(cx, |editor, cx| {
 6415                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6416                            })?
 6417                            .await;
 6418                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6419                    }
 6420                })
 6421            }
 6422        };
 6423
 6424        cx.spawn_in(window, async move |editor, cx| {
 6425            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6426            let code_actions = code_actions_task.await;
 6427            let spawn_straight_away = quick_launch
 6428                && resolved_tasks
 6429                    .as_ref()
 6430                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6431                && code_actions
 6432                    .as_ref()
 6433                    .is_none_or(|actions| actions.is_empty())
 6434                && debug_scenarios.is_empty();
 6435
 6436            editor.update_in(cx, |editor, window, cx| {
 6437                crate::hover_popover::hide_hover(editor, cx);
 6438                let actions = CodeActionContents::new(
 6439                    resolved_tasks,
 6440                    code_actions,
 6441                    debug_scenarios,
 6442                    task_context.unwrap_or_default(),
 6443                );
 6444
 6445                // Don't show the menu if there are no actions available
 6446                if actions.is_empty() {
 6447                    cx.notify();
 6448                    return Task::ready(Ok(()));
 6449                }
 6450
 6451                *editor.context_menu.borrow_mut() =
 6452                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6453                        buffer,
 6454                        actions,
 6455                        selected_item: Default::default(),
 6456                        scroll_handle: UniformListScrollHandle::default(),
 6457                        deployed_from,
 6458                    }));
 6459                cx.notify();
 6460                if spawn_straight_away
 6461                    && let Some(task) = editor.confirm_code_action(
 6462                        &ConfirmCodeAction { item_ix: Some(0) },
 6463                        window,
 6464                        cx,
 6465                    )
 6466                {
 6467                    return task;
 6468                }
 6469
 6470                Task::ready(Ok(()))
 6471            })
 6472        })
 6473        .detach_and_log_err(cx);
 6474    }
 6475
 6476    fn debug_scenarios(
 6477        &mut self,
 6478        resolved_tasks: &Option<ResolvedTasks>,
 6479        buffer: &Entity<Buffer>,
 6480        cx: &mut App,
 6481    ) -> Task<Vec<task::DebugScenario>> {
 6482        maybe!({
 6483            let project = self.project()?;
 6484            let dap_store = project.read(cx).dap_store();
 6485            let mut scenarios = vec![];
 6486            let resolved_tasks = resolved_tasks.as_ref()?;
 6487            let buffer = buffer.read(cx);
 6488            let language = buffer.language()?;
 6489            let file = buffer.file();
 6490            let debug_adapter = language_settings(language.name().into(), file, cx)
 6491                .debuggers
 6492                .first()
 6493                .map(SharedString::from)
 6494                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6495
 6496            dap_store.update(cx, |dap_store, cx| {
 6497                for (_, task) in &resolved_tasks.templates {
 6498                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6499                        task.original_task().clone(),
 6500                        debug_adapter.clone().into(),
 6501                        task.display_label().to_owned().into(),
 6502                        cx,
 6503                    );
 6504                    scenarios.push(maybe_scenario);
 6505                }
 6506            });
 6507            Some(cx.background_spawn(async move {
 6508                futures::future::join_all(scenarios)
 6509                    .await
 6510                    .into_iter()
 6511                    .flatten()
 6512                    .collect::<Vec<_>>()
 6513            }))
 6514        })
 6515        .unwrap_or_else(|| Task::ready(vec![]))
 6516    }
 6517
 6518    fn code_actions(
 6519        &mut self,
 6520        buffer_row: u32,
 6521        window: &mut Window,
 6522        cx: &mut Context<Self>,
 6523    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6524        let mut task = self.code_actions_task.take();
 6525        cx.spawn_in(window, async move |editor, cx| {
 6526            while let Some(prev_task) = task {
 6527                prev_task.await.log_err();
 6528                task = editor
 6529                    .update(cx, |this, _| this.code_actions_task.take())
 6530                    .ok()?;
 6531            }
 6532
 6533            editor
 6534                .update(cx, |editor, cx| {
 6535                    editor
 6536                        .available_code_actions
 6537                        .clone()
 6538                        .and_then(|(location, code_actions)| {
 6539                            let snapshot = location.buffer.read(cx).snapshot();
 6540                            let point_range = location.range.to_point(&snapshot);
 6541                            let point_range = point_range.start.row..=point_range.end.row;
 6542                            if point_range.contains(&buffer_row) {
 6543                                Some(code_actions)
 6544                            } else {
 6545                                None
 6546                            }
 6547                        })
 6548                })
 6549                .ok()
 6550                .flatten()
 6551        })
 6552    }
 6553
 6554    pub fn confirm_code_action(
 6555        &mut self,
 6556        action: &ConfirmCodeAction,
 6557        window: &mut Window,
 6558        cx: &mut Context<Self>,
 6559    ) -> Option<Task<Result<()>>> {
 6560        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6561
 6562        let actions_menu =
 6563            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6564                menu
 6565            } else {
 6566                return None;
 6567            };
 6568
 6569        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6570        let action = actions_menu.actions.get(action_ix)?;
 6571        let title = action.label();
 6572        let buffer = actions_menu.buffer;
 6573        let workspace = self.workspace()?;
 6574
 6575        match action {
 6576            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6577                workspace.update(cx, |workspace, cx| {
 6578                    workspace.schedule_resolved_task(
 6579                        task_source_kind,
 6580                        resolved_task,
 6581                        false,
 6582                        window,
 6583                        cx,
 6584                    );
 6585
 6586                    Some(Task::ready(Ok(())))
 6587                })
 6588            }
 6589            CodeActionsItem::CodeAction {
 6590                excerpt_id,
 6591                action,
 6592                provider,
 6593            } => {
 6594                let apply_code_action =
 6595                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6596                let workspace = workspace.downgrade();
 6597                Some(cx.spawn_in(window, async move |editor, cx| {
 6598                    let project_transaction = apply_code_action.await?;
 6599                    Self::open_project_transaction(
 6600                        &editor,
 6601                        workspace,
 6602                        project_transaction,
 6603                        title,
 6604                        cx,
 6605                    )
 6606                    .await
 6607                }))
 6608            }
 6609            CodeActionsItem::DebugScenario(scenario) => {
 6610                let context = actions_menu.actions.context;
 6611
 6612                workspace.update(cx, |workspace, cx| {
 6613                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6614                    workspace.start_debug_session(
 6615                        scenario,
 6616                        context,
 6617                        Some(buffer),
 6618                        None,
 6619                        window,
 6620                        cx,
 6621                    );
 6622                });
 6623                Some(Task::ready(Ok(())))
 6624            }
 6625        }
 6626    }
 6627
 6628    pub async fn open_project_transaction(
 6629        editor: &WeakEntity<Editor>,
 6630        workspace: WeakEntity<Workspace>,
 6631        transaction: ProjectTransaction,
 6632        title: String,
 6633        cx: &mut AsyncWindowContext,
 6634    ) -> Result<()> {
 6635        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6636        cx.update(|_, cx| {
 6637            entries.sort_unstable_by_key(|(buffer, _)| {
 6638                buffer.read(cx).file().map(|f| f.path().clone())
 6639            });
 6640        })?;
 6641        if entries.is_empty() {
 6642            return Ok(());
 6643        }
 6644
 6645        // If the project transaction's edits are all contained within this editor, then
 6646        // avoid opening a new editor to display them.
 6647
 6648        if let [(buffer, transaction)] = &*entries {
 6649            let excerpt = editor.update(cx, |editor, cx| {
 6650                editor
 6651                    .buffer()
 6652                    .read(cx)
 6653                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6654            })?;
 6655            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6656                && excerpted_buffer == *buffer
 6657            {
 6658                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6659                    let excerpt_range = excerpt_range.to_offset(buffer);
 6660                    buffer
 6661                        .edited_ranges_for_transaction::<usize>(transaction)
 6662                        .all(|range| {
 6663                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6664                        })
 6665                })?;
 6666
 6667                if all_edits_within_excerpt {
 6668                    return Ok(());
 6669                }
 6670            }
 6671        }
 6672
 6673        let mut ranges_to_highlight = Vec::new();
 6674        let excerpt_buffer = cx.new(|cx| {
 6675            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6676            for (buffer_handle, transaction) in &entries {
 6677                let edited_ranges = buffer_handle
 6678                    .read(cx)
 6679                    .edited_ranges_for_transaction::<Point>(transaction)
 6680                    .collect::<Vec<_>>();
 6681                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6682                    PathKey::for_buffer(buffer_handle, cx),
 6683                    buffer_handle.clone(),
 6684                    edited_ranges,
 6685                    multibuffer_context_lines(cx),
 6686                    cx,
 6687                );
 6688
 6689                ranges_to_highlight.extend(ranges);
 6690            }
 6691            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6692            multibuffer
 6693        })?;
 6694
 6695        workspace.update_in(cx, |workspace, window, cx| {
 6696            let project = workspace.project().clone();
 6697            let editor =
 6698                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6699            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6700            editor.update(cx, |editor, cx| {
 6701                editor.highlight_background::<Self>(
 6702                    &ranges_to_highlight,
 6703                    |_, theme| theme.colors().editor_highlighted_line_background,
 6704                    cx,
 6705                );
 6706            });
 6707        })?;
 6708
 6709        Ok(())
 6710    }
 6711
 6712    pub fn clear_code_action_providers(&mut self) {
 6713        self.code_action_providers.clear();
 6714        self.available_code_actions.take();
 6715    }
 6716
 6717    pub fn add_code_action_provider(
 6718        &mut self,
 6719        provider: Rc<dyn CodeActionProvider>,
 6720        window: &mut Window,
 6721        cx: &mut Context<Self>,
 6722    ) {
 6723        if self
 6724            .code_action_providers
 6725            .iter()
 6726            .any(|existing_provider| existing_provider.id() == provider.id())
 6727        {
 6728            return;
 6729        }
 6730
 6731        self.code_action_providers.push(provider);
 6732        self.refresh_code_actions(window, cx);
 6733    }
 6734
 6735    pub fn remove_code_action_provider(
 6736        &mut self,
 6737        id: Arc<str>,
 6738        window: &mut Window,
 6739        cx: &mut Context<Self>,
 6740    ) {
 6741        self.code_action_providers
 6742            .retain(|provider| provider.id() != id);
 6743        self.refresh_code_actions(window, cx);
 6744    }
 6745
 6746    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6747        !self.code_action_providers.is_empty()
 6748            && EditorSettings::get_global(cx).toolbar.code_actions
 6749    }
 6750
 6751    pub fn has_available_code_actions(&self) -> bool {
 6752        self.available_code_actions
 6753            .as_ref()
 6754            .is_some_and(|(_, actions)| !actions.is_empty())
 6755    }
 6756
 6757    fn render_inline_code_actions(
 6758        &self,
 6759        icon_size: ui::IconSize,
 6760        display_row: DisplayRow,
 6761        is_active: bool,
 6762        cx: &mut Context<Self>,
 6763    ) -> AnyElement {
 6764        let show_tooltip = !self.context_menu_visible();
 6765        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6766            .icon_size(icon_size)
 6767            .shape(ui::IconButtonShape::Square)
 6768            .icon_color(ui::Color::Hidden)
 6769            .toggle_state(is_active)
 6770            .when(show_tooltip, |this| {
 6771                this.tooltip({
 6772                    let focus_handle = self.focus_handle.clone();
 6773                    move |_window, cx| {
 6774                        Tooltip::for_action_in(
 6775                            "Toggle Code Actions",
 6776                            &ToggleCodeActions {
 6777                                deployed_from: None,
 6778                                quick_launch: false,
 6779                            },
 6780                            &focus_handle,
 6781                            cx,
 6782                        )
 6783                    }
 6784                })
 6785            })
 6786            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6787                window.focus(&editor.focus_handle(cx));
 6788                editor.toggle_code_actions(
 6789                    &crate::actions::ToggleCodeActions {
 6790                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6791                            display_row,
 6792                        )),
 6793                        quick_launch: false,
 6794                    },
 6795                    window,
 6796                    cx,
 6797                );
 6798            }))
 6799            .into_any_element()
 6800    }
 6801
 6802    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6803        &self.context_menu
 6804    }
 6805
 6806    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6807        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6808            cx.background_executor()
 6809                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6810                .await;
 6811
 6812            let (start_buffer, start, _, end, newest_selection) = this
 6813                .update(cx, |this, cx| {
 6814                    let newest_selection = this.selections.newest_anchor().clone();
 6815                    if newest_selection.head().diff_base_anchor.is_some() {
 6816                        return None;
 6817                    }
 6818                    let display_snapshot = this.display_snapshot(cx);
 6819                    let newest_selection_adjusted =
 6820                        this.selections.newest_adjusted(&display_snapshot);
 6821                    let buffer = this.buffer.read(cx);
 6822
 6823                    let (start_buffer, start) =
 6824                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6825                    let (end_buffer, end) =
 6826                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6827
 6828                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6829                })?
 6830                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6831                .context(
 6832                    "Expected selection to lie in a single buffer when refreshing code actions",
 6833                )?;
 6834            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6835                let providers = this.code_action_providers.clone();
 6836                let tasks = this
 6837                    .code_action_providers
 6838                    .iter()
 6839                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6840                    .collect::<Vec<_>>();
 6841                (providers, tasks)
 6842            })?;
 6843
 6844            let mut actions = Vec::new();
 6845            for (provider, provider_actions) in
 6846                providers.into_iter().zip(future::join_all(tasks).await)
 6847            {
 6848                if let Some(provider_actions) = provider_actions.log_err() {
 6849                    actions.extend(provider_actions.into_iter().map(|action| {
 6850                        AvailableCodeAction {
 6851                            excerpt_id: newest_selection.start.excerpt_id,
 6852                            action,
 6853                            provider: provider.clone(),
 6854                        }
 6855                    }));
 6856                }
 6857            }
 6858
 6859            this.update(cx, |this, cx| {
 6860                this.available_code_actions = if actions.is_empty() {
 6861                    None
 6862                } else {
 6863                    Some((
 6864                        Location {
 6865                            buffer: start_buffer,
 6866                            range: start..end,
 6867                        },
 6868                        actions.into(),
 6869                    ))
 6870                };
 6871                cx.notify();
 6872            })
 6873        }));
 6874    }
 6875
 6876    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6877        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6878            self.show_git_blame_inline = false;
 6879
 6880            self.show_git_blame_inline_delay_task =
 6881                Some(cx.spawn_in(window, async move |this, cx| {
 6882                    cx.background_executor().timer(delay).await;
 6883
 6884                    this.update(cx, |this, cx| {
 6885                        this.show_git_blame_inline = true;
 6886                        cx.notify();
 6887                    })
 6888                    .log_err();
 6889                }));
 6890        }
 6891    }
 6892
 6893    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6894        let snapshot = self.snapshot(window, cx);
 6895        let cursor = self
 6896            .selections
 6897            .newest::<Point>(&snapshot.display_snapshot)
 6898            .head();
 6899        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6900        else {
 6901            return;
 6902        };
 6903
 6904        if self.blame.is_none() {
 6905            self.start_git_blame(true, window, cx);
 6906        }
 6907        let Some(blame) = self.blame.as_ref() else {
 6908            return;
 6909        };
 6910
 6911        let row_info = RowInfo {
 6912            buffer_id: Some(buffer.remote_id()),
 6913            buffer_row: Some(point.row),
 6914            ..Default::default()
 6915        };
 6916        let Some((buffer, blame_entry)) = blame
 6917            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6918            .flatten()
 6919        else {
 6920            return;
 6921        };
 6922
 6923        let anchor = self.selections.newest_anchor().head();
 6924        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 6925        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6926            self.show_blame_popover(
 6927                buffer,
 6928                &blame_entry,
 6929                position + last_bounds.origin,
 6930                true,
 6931                cx,
 6932            );
 6933        };
 6934    }
 6935
 6936    fn show_blame_popover(
 6937        &mut self,
 6938        buffer: BufferId,
 6939        blame_entry: &BlameEntry,
 6940        position: gpui::Point<Pixels>,
 6941        ignore_timeout: bool,
 6942        cx: &mut Context<Self>,
 6943    ) {
 6944        if let Some(state) = &mut self.inline_blame_popover {
 6945            state.hide_task.take();
 6946        } else {
 6947            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6948            let blame_entry = blame_entry.clone();
 6949            let show_task = cx.spawn(async move |editor, cx| {
 6950                if !ignore_timeout {
 6951                    cx.background_executor()
 6952                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6953                        .await;
 6954                }
 6955                editor
 6956                    .update(cx, |editor, cx| {
 6957                        editor.inline_blame_popover_show_task.take();
 6958                        let Some(blame) = editor.blame.as_ref() else {
 6959                            return;
 6960                        };
 6961                        let blame = blame.read(cx);
 6962                        let details = blame.details_for_entry(buffer, &blame_entry);
 6963                        let markdown = cx.new(|cx| {
 6964                            Markdown::new(
 6965                                details
 6966                                    .as_ref()
 6967                                    .map(|message| message.message.clone())
 6968                                    .unwrap_or_default(),
 6969                                None,
 6970                                None,
 6971                                cx,
 6972                            )
 6973                        });
 6974                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6975                            position,
 6976                            hide_task: None,
 6977                            popover_bounds: None,
 6978                            popover_state: InlineBlamePopoverState {
 6979                                scroll_handle: ScrollHandle::new(),
 6980                                commit_message: details,
 6981                                markdown,
 6982                            },
 6983                            keyboard_grace: ignore_timeout,
 6984                        });
 6985                        cx.notify();
 6986                    })
 6987                    .ok();
 6988            });
 6989            self.inline_blame_popover_show_task = Some(show_task);
 6990        }
 6991    }
 6992
 6993    pub fn has_mouse_context_menu(&self) -> bool {
 6994        self.mouse_context_menu.is_some()
 6995    }
 6996
 6997    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6998        self.inline_blame_popover_show_task.take();
 6999        if let Some(state) = &mut self.inline_blame_popover {
 7000            let hide_task = cx.spawn(async move |editor, cx| {
 7001                if !ignore_timeout {
 7002                    cx.background_executor()
 7003                        .timer(std::time::Duration::from_millis(100))
 7004                        .await;
 7005                }
 7006                editor
 7007                    .update(cx, |editor, cx| {
 7008                        editor.inline_blame_popover.take();
 7009                        cx.notify();
 7010                    })
 7011                    .ok();
 7012            });
 7013            state.hide_task = Some(hide_task);
 7014            true
 7015        } else {
 7016            false
 7017        }
 7018    }
 7019
 7020    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7021        if self.pending_rename.is_some() {
 7022            return None;
 7023        }
 7024
 7025        let provider = self.semantics_provider.clone()?;
 7026        let buffer = self.buffer.read(cx);
 7027        let newest_selection = self.selections.newest_anchor().clone();
 7028        let cursor_position = newest_selection.head();
 7029        let (cursor_buffer, cursor_buffer_position) =
 7030            buffer.text_anchor_for_position(cursor_position, cx)?;
 7031        let (tail_buffer, tail_buffer_position) =
 7032            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7033        if cursor_buffer != tail_buffer {
 7034            return None;
 7035        }
 7036
 7037        let snapshot = cursor_buffer.read(cx).snapshot();
 7038        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7039        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7040        if start_word_range != end_word_range {
 7041            self.document_highlights_task.take();
 7042            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 7043            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 7044            return None;
 7045        }
 7046
 7047        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7048        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7049            cx.background_executor()
 7050                .timer(Duration::from_millis(debounce))
 7051                .await;
 7052
 7053            let highlights = if let Some(highlights) = cx
 7054                .update(|cx| {
 7055                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7056                })
 7057                .ok()
 7058                .flatten()
 7059            {
 7060                highlights.await.log_err()
 7061            } else {
 7062                None
 7063            };
 7064
 7065            if let Some(highlights) = highlights {
 7066                this.update(cx, |this, cx| {
 7067                    if this.pending_rename.is_some() {
 7068                        return;
 7069                    }
 7070
 7071                    let buffer = this.buffer.read(cx);
 7072                    if buffer
 7073                        .text_anchor_for_position(cursor_position, cx)
 7074                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7075                    {
 7076                        return;
 7077                    }
 7078
 7079                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7080                    let mut write_ranges = Vec::new();
 7081                    let mut read_ranges = Vec::new();
 7082                    for highlight in highlights {
 7083                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7084                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7085                        {
 7086                            let start = highlight
 7087                                .range
 7088                                .start
 7089                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7090                            let end = highlight
 7091                                .range
 7092                                .end
 7093                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7094                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7095                                continue;
 7096                            }
 7097
 7098                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7099                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7100                                write_ranges.push(range);
 7101                            } else {
 7102                                read_ranges.push(range);
 7103                            }
 7104                        }
 7105                    }
 7106
 7107                    this.highlight_background::<DocumentHighlightRead>(
 7108                        &read_ranges,
 7109                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7110                        cx,
 7111                    );
 7112                    this.highlight_background::<DocumentHighlightWrite>(
 7113                        &write_ranges,
 7114                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7115                        cx,
 7116                    );
 7117                    cx.notify();
 7118                })
 7119                .log_err();
 7120            }
 7121        }));
 7122        None
 7123    }
 7124
 7125    fn prepare_highlight_query_from_selection(
 7126        &mut self,
 7127        window: &Window,
 7128        cx: &mut Context<Editor>,
 7129    ) -> Option<(String, Range<Anchor>)> {
 7130        if matches!(self.mode, EditorMode::SingleLine) {
 7131            return None;
 7132        }
 7133        if !EditorSettings::get_global(cx).selection_highlight {
 7134            return None;
 7135        }
 7136        if self.selections.count() != 1 || self.selections.line_mode() {
 7137            return None;
 7138        }
 7139        let snapshot = self.snapshot(window, cx);
 7140        let selection = self.selections.newest::<Point>(&snapshot);
 7141        // If the selection spans multiple rows OR it is empty
 7142        if selection.start.row != selection.end.row
 7143            || selection.start.column == selection.end.column
 7144        {
 7145            return None;
 7146        }
 7147        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7148        let query = snapshot
 7149            .buffer_snapshot()
 7150            .text_for_range(selection_anchor_range.clone())
 7151            .collect::<String>();
 7152        if query.trim().is_empty() {
 7153            return None;
 7154        }
 7155        Some((query, selection_anchor_range))
 7156    }
 7157
 7158    #[ztracing::instrument(skip_all)]
 7159    fn update_selection_occurrence_highlights(
 7160        &mut self,
 7161        query_text: String,
 7162        query_range: Range<Anchor>,
 7163        multi_buffer_range_to_query: Range<Point>,
 7164        use_debounce: bool,
 7165        window: &mut Window,
 7166        cx: &mut Context<Editor>,
 7167    ) -> Task<()> {
 7168        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7169        cx.spawn_in(window, async move |editor, cx| {
 7170            if use_debounce {
 7171                cx.background_executor()
 7172                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7173                    .await;
 7174            }
 7175            let match_task = cx.background_spawn(async move {
 7176                let buffer_ranges = multi_buffer_snapshot
 7177                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7178                    .into_iter()
 7179                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7180                let mut match_ranges = Vec::new();
 7181                let Ok(regex) = project::search::SearchQuery::text(
 7182                    query_text.clone(),
 7183                    false,
 7184                    false,
 7185                    false,
 7186                    Default::default(),
 7187                    Default::default(),
 7188                    false,
 7189                    None,
 7190                ) else {
 7191                    return Vec::default();
 7192                };
 7193                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7194                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7195                    match_ranges.extend(
 7196                        regex
 7197                            .search(
 7198                                buffer_snapshot,
 7199                                Some(search_range.start.0..search_range.end.0),
 7200                            )
 7201                            .await
 7202                            .into_iter()
 7203                            .filter_map(|match_range| {
 7204                                let match_start = buffer_snapshot
 7205                                    .anchor_after(search_range.start + match_range.start);
 7206                                let match_end = buffer_snapshot
 7207                                    .anchor_before(search_range.start + match_range.end);
 7208                                let match_anchor_range =
 7209                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7210                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7211                            }),
 7212                    );
 7213                }
 7214                match_ranges
 7215            });
 7216            let match_ranges = match_task.await;
 7217            editor
 7218                .update_in(cx, |editor, _, cx| {
 7219                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7220                    if !match_ranges.is_empty() {
 7221                        editor.highlight_background::<SelectedTextHighlight>(
 7222                            &match_ranges,
 7223                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7224                            cx,
 7225                        )
 7226                    }
 7227                })
 7228                .log_err();
 7229        })
 7230    }
 7231
 7232    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7233        struct NewlineFold;
 7234        let type_id = std::any::TypeId::of::<NewlineFold>();
 7235        if !self.mode.is_single_line() {
 7236            return;
 7237        }
 7238        let snapshot = self.snapshot(window, cx);
 7239        if snapshot.buffer_snapshot().max_point().row == 0 {
 7240            return;
 7241        }
 7242        let task = cx.background_spawn(async move {
 7243            let new_newlines = snapshot
 7244                .buffer_chars_at(MultiBufferOffset(0))
 7245                .filter_map(|(c, i)| {
 7246                    if c == '\n' {
 7247                        Some(
 7248                            snapshot.buffer_snapshot().anchor_after(i)
 7249                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7250                        )
 7251                    } else {
 7252                        None
 7253                    }
 7254                })
 7255                .collect::<Vec<_>>();
 7256            let existing_newlines = snapshot
 7257                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7258                .filter_map(|fold| {
 7259                    if fold.placeholder.type_tag == Some(type_id) {
 7260                        Some(fold.range.start..fold.range.end)
 7261                    } else {
 7262                        None
 7263                    }
 7264                })
 7265                .collect::<Vec<_>>();
 7266
 7267            (new_newlines, existing_newlines)
 7268        });
 7269        self.folding_newlines = cx.spawn(async move |this, cx| {
 7270            let (new_newlines, existing_newlines) = task.await;
 7271            if new_newlines == existing_newlines {
 7272                return;
 7273            }
 7274            let placeholder = FoldPlaceholder {
 7275                render: Arc::new(move |_, _, cx| {
 7276                    div()
 7277                        .bg(cx.theme().status().hint_background)
 7278                        .border_b_1()
 7279                        .size_full()
 7280                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7281                        .border_color(cx.theme().status().hint)
 7282                        .child("\\n")
 7283                        .into_any()
 7284                }),
 7285                constrain_width: false,
 7286                merge_adjacent: false,
 7287                type_tag: Some(type_id),
 7288            };
 7289            let creases = new_newlines
 7290                .into_iter()
 7291                .map(|range| Crease::simple(range, placeholder.clone()))
 7292                .collect();
 7293            this.update(cx, |this, cx| {
 7294                this.display_map.update(cx, |display_map, cx| {
 7295                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7296                    display_map.fold(creases, cx);
 7297                });
 7298            })
 7299            .ok();
 7300        });
 7301    }
 7302
 7303    #[ztracing::instrument(skip_all)]
 7304    fn refresh_selected_text_highlights(
 7305        &mut self,
 7306        on_buffer_edit: bool,
 7307        window: &mut Window,
 7308        cx: &mut Context<Editor>,
 7309    ) {
 7310        let Some((query_text, query_range)) =
 7311            self.prepare_highlight_query_from_selection(window, cx)
 7312        else {
 7313            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7314            self.quick_selection_highlight_task.take();
 7315            self.debounced_selection_highlight_task.take();
 7316            return;
 7317        };
 7318        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7319        if on_buffer_edit
 7320            || self
 7321                .quick_selection_highlight_task
 7322                .as_ref()
 7323                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7324        {
 7325            let multi_buffer_visible_start = self
 7326                .scroll_manager
 7327                .anchor()
 7328                .anchor
 7329                .to_point(&multi_buffer_snapshot);
 7330            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7331                multi_buffer_visible_start
 7332                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7333                Bias::Left,
 7334            );
 7335            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7336            self.quick_selection_highlight_task = Some((
 7337                query_range.clone(),
 7338                self.update_selection_occurrence_highlights(
 7339                    query_text.clone(),
 7340                    query_range.clone(),
 7341                    multi_buffer_visible_range,
 7342                    false,
 7343                    window,
 7344                    cx,
 7345                ),
 7346            ));
 7347        }
 7348        if on_buffer_edit
 7349            || self
 7350                .debounced_selection_highlight_task
 7351                .as_ref()
 7352                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7353        {
 7354            let multi_buffer_start = multi_buffer_snapshot
 7355                .anchor_before(MultiBufferOffset(0))
 7356                .to_point(&multi_buffer_snapshot);
 7357            let multi_buffer_end = multi_buffer_snapshot
 7358                .anchor_after(multi_buffer_snapshot.len())
 7359                .to_point(&multi_buffer_snapshot);
 7360            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7361            self.debounced_selection_highlight_task = Some((
 7362                query_range.clone(),
 7363                self.update_selection_occurrence_highlights(
 7364                    query_text,
 7365                    query_range,
 7366                    multi_buffer_full_range,
 7367                    true,
 7368                    window,
 7369                    cx,
 7370                ),
 7371            ));
 7372        }
 7373    }
 7374
 7375    pub fn refresh_edit_prediction(
 7376        &mut self,
 7377        debounce: bool,
 7378        user_requested: bool,
 7379        window: &mut Window,
 7380        cx: &mut Context<Self>,
 7381    ) -> Option<()> {
 7382        if DisableAiSettings::get_global(cx).disable_ai {
 7383            return None;
 7384        }
 7385
 7386        let provider = self.edit_prediction_provider()?;
 7387        let cursor = self.selections.newest_anchor().head();
 7388        let (buffer, cursor_buffer_position) =
 7389            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7390
 7391        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7392            self.discard_edit_prediction(false, cx);
 7393            return None;
 7394        }
 7395
 7396        self.update_visible_edit_prediction(window, cx);
 7397
 7398        if !user_requested
 7399            && (!self.should_show_edit_predictions()
 7400                || !self.is_focused(window)
 7401                || buffer.read(cx).is_empty())
 7402        {
 7403            self.discard_edit_prediction(false, cx);
 7404            return None;
 7405        }
 7406
 7407        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7408        Some(())
 7409    }
 7410
 7411    fn show_edit_predictions_in_menu(&self) -> bool {
 7412        match self.edit_prediction_settings {
 7413            EditPredictionSettings::Disabled => false,
 7414            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7415        }
 7416    }
 7417
 7418    pub fn edit_predictions_enabled(&self) -> bool {
 7419        match self.edit_prediction_settings {
 7420            EditPredictionSettings::Disabled => false,
 7421            EditPredictionSettings::Enabled { .. } => true,
 7422        }
 7423    }
 7424
 7425    fn edit_prediction_requires_modifier(&self) -> bool {
 7426        match self.edit_prediction_settings {
 7427            EditPredictionSettings::Disabled => false,
 7428            EditPredictionSettings::Enabled {
 7429                preview_requires_modifier,
 7430                ..
 7431            } => preview_requires_modifier,
 7432        }
 7433    }
 7434
 7435    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7436        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7437            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7438            self.discard_edit_prediction(false, cx);
 7439        } else {
 7440            let selection = self.selections.newest_anchor();
 7441            let cursor = selection.head();
 7442
 7443            if let Some((buffer, cursor_buffer_position)) =
 7444                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7445            {
 7446                self.edit_prediction_settings =
 7447                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7448            }
 7449        }
 7450    }
 7451
 7452    fn edit_prediction_settings_at_position(
 7453        &self,
 7454        buffer: &Entity<Buffer>,
 7455        buffer_position: language::Anchor,
 7456        cx: &App,
 7457    ) -> EditPredictionSettings {
 7458        if !self.mode.is_full()
 7459            || !self.show_edit_predictions_override.unwrap_or(true)
 7460            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7461        {
 7462            return EditPredictionSettings::Disabled;
 7463        }
 7464
 7465        let buffer = buffer.read(cx);
 7466
 7467        let file = buffer.file();
 7468
 7469        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7470            return EditPredictionSettings::Disabled;
 7471        };
 7472
 7473        let by_provider = matches!(
 7474            self.menu_edit_predictions_policy,
 7475            MenuEditPredictionsPolicy::ByProvider
 7476        );
 7477
 7478        let show_in_menu = by_provider
 7479            && self
 7480                .edit_prediction_provider
 7481                .as_ref()
 7482                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7483
 7484        let preview_requires_modifier =
 7485            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7486
 7487        EditPredictionSettings::Enabled {
 7488            show_in_menu,
 7489            preview_requires_modifier,
 7490        }
 7491    }
 7492
 7493    fn should_show_edit_predictions(&self) -> bool {
 7494        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7495    }
 7496
 7497    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7498        matches!(
 7499            self.edit_prediction_preview,
 7500            EditPredictionPreview::Active { .. }
 7501        )
 7502    }
 7503
 7504    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7505        let cursor = self.selections.newest_anchor().head();
 7506        if let Some((buffer, cursor_position)) =
 7507            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7508        {
 7509            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7510        } else {
 7511            false
 7512        }
 7513    }
 7514
 7515    pub fn supports_minimap(&self, cx: &App) -> bool {
 7516        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7517    }
 7518
 7519    fn edit_predictions_enabled_in_buffer(
 7520        &self,
 7521        buffer: &Entity<Buffer>,
 7522        buffer_position: language::Anchor,
 7523        cx: &App,
 7524    ) -> bool {
 7525        maybe!({
 7526            if self.read_only(cx) {
 7527                return Some(false);
 7528            }
 7529            let provider = self.edit_prediction_provider()?;
 7530            if !provider.is_enabled(buffer, buffer_position, cx) {
 7531                return Some(false);
 7532            }
 7533            let buffer = buffer.read(cx);
 7534            let Some(file) = buffer.file() else {
 7535                return Some(true);
 7536            };
 7537            let settings = all_language_settings(Some(file), cx);
 7538            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7539        })
 7540        .unwrap_or(false)
 7541    }
 7542
 7543    fn cycle_edit_prediction(
 7544        &mut self,
 7545        direction: Direction,
 7546        window: &mut Window,
 7547        cx: &mut Context<Self>,
 7548    ) -> Option<()> {
 7549        let provider = self.edit_prediction_provider()?;
 7550        let cursor = self.selections.newest_anchor().head();
 7551        let (buffer, cursor_buffer_position) =
 7552            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7553        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7554            return None;
 7555        }
 7556
 7557        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7558        self.update_visible_edit_prediction(window, cx);
 7559
 7560        Some(())
 7561    }
 7562
 7563    pub fn show_edit_prediction(
 7564        &mut self,
 7565        _: &ShowEditPrediction,
 7566        window: &mut Window,
 7567        cx: &mut Context<Self>,
 7568    ) {
 7569        if !self.has_active_edit_prediction() {
 7570            self.refresh_edit_prediction(false, true, window, cx);
 7571            return;
 7572        }
 7573
 7574        self.update_visible_edit_prediction(window, cx);
 7575    }
 7576
 7577    pub fn display_cursor_names(
 7578        &mut self,
 7579        _: &DisplayCursorNames,
 7580        window: &mut Window,
 7581        cx: &mut Context<Self>,
 7582    ) {
 7583        self.show_cursor_names(window, cx);
 7584    }
 7585
 7586    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7587        self.show_cursor_names = true;
 7588        cx.notify();
 7589        cx.spawn_in(window, async move |this, cx| {
 7590            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7591            this.update(cx, |this, cx| {
 7592                this.show_cursor_names = false;
 7593                cx.notify()
 7594            })
 7595            .ok()
 7596        })
 7597        .detach();
 7598    }
 7599
 7600    pub fn next_edit_prediction(
 7601        &mut self,
 7602        _: &NextEditPrediction,
 7603        window: &mut Window,
 7604        cx: &mut Context<Self>,
 7605    ) {
 7606        if self.has_active_edit_prediction() {
 7607            self.cycle_edit_prediction(Direction::Next, window, cx);
 7608        } else {
 7609            let is_copilot_disabled = self
 7610                .refresh_edit_prediction(false, true, window, cx)
 7611                .is_none();
 7612            if is_copilot_disabled {
 7613                cx.propagate();
 7614            }
 7615        }
 7616    }
 7617
 7618    pub fn previous_edit_prediction(
 7619        &mut self,
 7620        _: &PreviousEditPrediction,
 7621        window: &mut Window,
 7622        cx: &mut Context<Self>,
 7623    ) {
 7624        if self.has_active_edit_prediction() {
 7625            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7626        } else {
 7627            let is_copilot_disabled = self
 7628                .refresh_edit_prediction(false, true, window, cx)
 7629                .is_none();
 7630            if is_copilot_disabled {
 7631                cx.propagate();
 7632            }
 7633        }
 7634    }
 7635
 7636    pub fn accept_edit_prediction(
 7637        &mut self,
 7638        _: &AcceptEditPrediction,
 7639        window: &mut Window,
 7640        cx: &mut Context<Self>,
 7641    ) {
 7642        if self.show_edit_predictions_in_menu() {
 7643            self.hide_context_menu(window, cx);
 7644        }
 7645
 7646        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7647            return;
 7648        };
 7649
 7650        match &active_edit_prediction.completion {
 7651            EditPrediction::MoveWithin { target, .. } => {
 7652                let target = *target;
 7653
 7654                if let Some(position_map) = &self.last_position_map {
 7655                    if position_map
 7656                        .visible_row_range
 7657                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7658                        || !self.edit_prediction_requires_modifier()
 7659                    {
 7660                        self.unfold_ranges(&[target..target], true, false, cx);
 7661                        // Note that this is also done in vim's handler of the Tab action.
 7662                        self.change_selections(
 7663                            SelectionEffects::scroll(Autoscroll::newest()),
 7664                            window,
 7665                            cx,
 7666                            |selections| {
 7667                                selections.select_anchor_ranges([target..target]);
 7668                            },
 7669                        );
 7670                        self.clear_row_highlights::<EditPredictionPreview>();
 7671
 7672                        self.edit_prediction_preview
 7673                            .set_previous_scroll_position(None);
 7674                    } else {
 7675                        self.edit_prediction_preview
 7676                            .set_previous_scroll_position(Some(
 7677                                position_map.snapshot.scroll_anchor,
 7678                            ));
 7679
 7680                        self.highlight_rows::<EditPredictionPreview>(
 7681                            target..target,
 7682                            cx.theme().colors().editor_highlighted_line_background,
 7683                            RowHighlightOptions {
 7684                                autoscroll: true,
 7685                                ..Default::default()
 7686                            },
 7687                            cx,
 7688                        );
 7689                        self.request_autoscroll(Autoscroll::fit(), cx);
 7690                    }
 7691                }
 7692            }
 7693            EditPrediction::MoveOutside { snapshot, target } => {
 7694                if let Some(workspace) = self.workspace() {
 7695                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7696                        .detach_and_log_err(cx);
 7697                }
 7698            }
 7699            EditPrediction::Edit { edits, .. } => {
 7700                self.report_edit_prediction_event(
 7701                    active_edit_prediction.completion_id.clone(),
 7702                    true,
 7703                    cx,
 7704                );
 7705
 7706                if let Some(provider) = self.edit_prediction_provider() {
 7707                    provider.accept(cx);
 7708                }
 7709
 7710                // Store the transaction ID and selections before applying the edit
 7711                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7712
 7713                let snapshot = self.buffer.read(cx).snapshot(cx);
 7714                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7715
 7716                self.buffer.update(cx, |buffer, cx| {
 7717                    buffer.edit(edits.iter().cloned(), None, cx)
 7718                });
 7719
 7720                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7721                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7722                });
 7723
 7724                let selections = self.selections.disjoint_anchors_arc();
 7725                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7726                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7727                    if has_new_transaction {
 7728                        self.selection_history
 7729                            .insert_transaction(transaction_id_now, selections);
 7730                    }
 7731                }
 7732
 7733                self.update_visible_edit_prediction(window, cx);
 7734                if self.active_edit_prediction.is_none() {
 7735                    self.refresh_edit_prediction(true, true, window, cx);
 7736                }
 7737
 7738                cx.notify();
 7739            }
 7740        }
 7741
 7742        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7743    }
 7744
 7745    pub fn accept_partial_edit_prediction(
 7746        &mut self,
 7747        _: &AcceptPartialEditPrediction,
 7748        window: &mut Window,
 7749        cx: &mut Context<Self>,
 7750    ) {
 7751        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7752            return;
 7753        };
 7754        if self.selections.count() != 1 {
 7755            return;
 7756        }
 7757
 7758        match &active_edit_prediction.completion {
 7759            EditPrediction::MoveWithin { target, .. } => {
 7760                let target = *target;
 7761                self.change_selections(
 7762                    SelectionEffects::scroll(Autoscroll::newest()),
 7763                    window,
 7764                    cx,
 7765                    |selections| {
 7766                        selections.select_anchor_ranges([target..target]);
 7767                    },
 7768                );
 7769            }
 7770            EditPrediction::MoveOutside { snapshot, target } => {
 7771                if let Some(workspace) = self.workspace() {
 7772                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7773                        .detach_and_log_err(cx);
 7774                }
 7775            }
 7776            EditPrediction::Edit { edits, .. } => {
 7777                self.report_edit_prediction_event(
 7778                    active_edit_prediction.completion_id.clone(),
 7779                    true,
 7780                    cx,
 7781                );
 7782
 7783                // Find an insertion that starts at the cursor position.
 7784                let snapshot = self.buffer.read(cx).snapshot(cx);
 7785                let cursor_offset = self
 7786                    .selections
 7787                    .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7788                    .head();
 7789                let insertion = edits.iter().find_map(|(range, text)| {
 7790                    let range = range.to_offset(&snapshot);
 7791                    if range.is_empty() && range.start == cursor_offset {
 7792                        Some(text)
 7793                    } else {
 7794                        None
 7795                    }
 7796                });
 7797
 7798                if let Some(text) = insertion {
 7799                    let mut partial_completion = text
 7800                        .chars()
 7801                        .by_ref()
 7802                        .take_while(|c| c.is_alphabetic())
 7803                        .collect::<String>();
 7804                    if partial_completion.is_empty() {
 7805                        partial_completion = text
 7806                            .chars()
 7807                            .by_ref()
 7808                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7809                            .collect::<String>();
 7810                    }
 7811
 7812                    cx.emit(EditorEvent::InputHandled {
 7813                        utf16_range_to_replace: None,
 7814                        text: partial_completion.clone().into(),
 7815                    });
 7816
 7817                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7818
 7819                    self.refresh_edit_prediction(true, true, window, cx);
 7820                    cx.notify();
 7821                } else {
 7822                    self.accept_edit_prediction(&Default::default(), window, cx);
 7823                }
 7824            }
 7825        }
 7826    }
 7827
 7828    fn discard_edit_prediction(
 7829        &mut self,
 7830        should_report_edit_prediction_event: bool,
 7831        cx: &mut Context<Self>,
 7832    ) -> bool {
 7833        if should_report_edit_prediction_event {
 7834            let completion_id = self
 7835                .active_edit_prediction
 7836                .as_ref()
 7837                .and_then(|active_completion| active_completion.completion_id.clone());
 7838
 7839            self.report_edit_prediction_event(completion_id, false, cx);
 7840        }
 7841
 7842        if let Some(provider) = self.edit_prediction_provider() {
 7843            provider.discard(cx);
 7844        }
 7845
 7846        self.take_active_edit_prediction(cx)
 7847    }
 7848
 7849    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7850        let Some(provider) = self.edit_prediction_provider() else {
 7851            return;
 7852        };
 7853
 7854        let Some((_, buffer, _)) = self
 7855            .buffer
 7856            .read(cx)
 7857            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7858        else {
 7859            return;
 7860        };
 7861
 7862        let extension = buffer
 7863            .read(cx)
 7864            .file()
 7865            .and_then(|file| Some(file.path().extension()?.to_string()));
 7866
 7867        let event_type = match accepted {
 7868            true => "Edit Prediction Accepted",
 7869            false => "Edit Prediction Discarded",
 7870        };
 7871        telemetry::event!(
 7872            event_type,
 7873            provider = provider.name(),
 7874            prediction_id = id,
 7875            suggestion_accepted = accepted,
 7876            file_extension = extension,
 7877        );
 7878    }
 7879
 7880    fn open_editor_at_anchor(
 7881        snapshot: &language::BufferSnapshot,
 7882        target: language::Anchor,
 7883        workspace: &Entity<Workspace>,
 7884        window: &mut Window,
 7885        cx: &mut App,
 7886    ) -> Task<Result<()>> {
 7887        workspace.update(cx, |workspace, cx| {
 7888            let path = snapshot.file().map(|file| file.full_path(cx));
 7889            let Some(path) =
 7890                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7891            else {
 7892                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7893            };
 7894            let target = text::ToPoint::to_point(&target, snapshot);
 7895            let item = workspace.open_path(path, None, true, window, cx);
 7896            window.spawn(cx, async move |cx| {
 7897                let Some(editor) = item.await?.downcast::<Editor>() else {
 7898                    return Ok(());
 7899                };
 7900                editor
 7901                    .update_in(cx, |editor, window, cx| {
 7902                        editor.go_to_singleton_buffer_point(target, window, cx);
 7903                    })
 7904                    .ok();
 7905                anyhow::Ok(())
 7906            })
 7907        })
 7908    }
 7909
 7910    pub fn has_active_edit_prediction(&self) -> bool {
 7911        self.active_edit_prediction.is_some()
 7912    }
 7913
 7914    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7915        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7916            return false;
 7917        };
 7918
 7919        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7920        self.clear_highlights::<EditPredictionHighlight>(cx);
 7921        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7922        true
 7923    }
 7924
 7925    /// Returns true when we're displaying the edit prediction popover below the cursor
 7926    /// like we are not previewing and the LSP autocomplete menu is visible
 7927    /// or we are in `when_holding_modifier` mode.
 7928    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7929        if self.edit_prediction_preview_is_active()
 7930            || !self.show_edit_predictions_in_menu()
 7931            || !self.edit_predictions_enabled()
 7932        {
 7933            return false;
 7934        }
 7935
 7936        if self.has_visible_completions_menu() {
 7937            return true;
 7938        }
 7939
 7940        has_completion && self.edit_prediction_requires_modifier()
 7941    }
 7942
 7943    fn handle_modifiers_changed(
 7944        &mut self,
 7945        modifiers: Modifiers,
 7946        position_map: &PositionMap,
 7947        window: &mut Window,
 7948        cx: &mut Context<Self>,
 7949    ) {
 7950        // Ensure that the edit prediction preview is updated, even when not
 7951        // enabled, if there's an active edit prediction preview.
 7952        if self.show_edit_predictions_in_menu()
 7953            || matches!(
 7954                self.edit_prediction_preview,
 7955                EditPredictionPreview::Active { .. }
 7956            )
 7957        {
 7958            self.update_edit_prediction_preview(&modifiers, window, cx);
 7959        }
 7960
 7961        self.update_selection_mode(&modifiers, position_map, window, cx);
 7962
 7963        let mouse_position = window.mouse_position();
 7964        if !position_map.text_hitbox.is_hovered(window) {
 7965            return;
 7966        }
 7967
 7968        self.update_hovered_link(
 7969            position_map.point_for_position(mouse_position),
 7970            &position_map.snapshot,
 7971            modifiers,
 7972            window,
 7973            cx,
 7974        )
 7975    }
 7976
 7977    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7978        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7979            MultiCursorModifier::Alt => modifiers.secondary(),
 7980            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7981        }
 7982    }
 7983
 7984    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7985        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7986            MultiCursorModifier::Alt => modifiers.alt,
 7987            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7988        }
 7989    }
 7990
 7991    fn columnar_selection_mode(
 7992        modifiers: &Modifiers,
 7993        cx: &mut Context<Self>,
 7994    ) -> Option<ColumnarMode> {
 7995        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7996            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7997                Some(ColumnarMode::FromMouse)
 7998            } else if Self::is_alt_pressed(modifiers, cx) {
 7999                Some(ColumnarMode::FromSelection)
 8000            } else {
 8001                None
 8002            }
 8003        } else {
 8004            None
 8005        }
 8006    }
 8007
 8008    fn update_selection_mode(
 8009        &mut self,
 8010        modifiers: &Modifiers,
 8011        position_map: &PositionMap,
 8012        window: &mut Window,
 8013        cx: &mut Context<Self>,
 8014    ) {
 8015        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8016            return;
 8017        };
 8018        if self.selections.pending_anchor().is_none() {
 8019            return;
 8020        }
 8021
 8022        let mouse_position = window.mouse_position();
 8023        let point_for_position = position_map.point_for_position(mouse_position);
 8024        let position = point_for_position.previous_valid;
 8025
 8026        self.select(
 8027            SelectPhase::BeginColumnar {
 8028                position,
 8029                reset: false,
 8030                mode,
 8031                goal_column: point_for_position.exact_unclipped.column(),
 8032            },
 8033            window,
 8034            cx,
 8035        );
 8036    }
 8037
 8038    fn update_edit_prediction_preview(
 8039        &mut self,
 8040        modifiers: &Modifiers,
 8041        window: &mut Window,
 8042        cx: &mut Context<Self>,
 8043    ) {
 8044        let mut modifiers_held = false;
 8045        if let Some(accept_keystroke) = self
 8046            .accept_edit_prediction_keybind(false, window, cx)
 8047            .keystroke()
 8048        {
 8049            modifiers_held = modifiers_held
 8050                || (accept_keystroke.modifiers() == modifiers
 8051                    && accept_keystroke.modifiers().modified());
 8052        };
 8053        if let Some(accept_partial_keystroke) = self
 8054            .accept_edit_prediction_keybind(true, window, cx)
 8055            .keystroke()
 8056        {
 8057            modifiers_held = modifiers_held
 8058                || (accept_partial_keystroke.modifiers() == modifiers
 8059                    && accept_partial_keystroke.modifiers().modified());
 8060        }
 8061
 8062        if modifiers_held {
 8063            if matches!(
 8064                self.edit_prediction_preview,
 8065                EditPredictionPreview::Inactive { .. }
 8066            ) {
 8067                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 8068                    provider.provider.did_show(cx)
 8069                }
 8070
 8071                self.edit_prediction_preview = EditPredictionPreview::Active {
 8072                    previous_scroll_position: None,
 8073                    since: Instant::now(),
 8074                };
 8075
 8076                self.update_visible_edit_prediction(window, cx);
 8077                cx.notify();
 8078            }
 8079        } else if let EditPredictionPreview::Active {
 8080            previous_scroll_position,
 8081            since,
 8082        } = self.edit_prediction_preview
 8083        {
 8084            if let (Some(previous_scroll_position), Some(position_map)) =
 8085                (previous_scroll_position, self.last_position_map.as_ref())
 8086            {
 8087                self.set_scroll_position(
 8088                    previous_scroll_position
 8089                        .scroll_position(&position_map.snapshot.display_snapshot),
 8090                    window,
 8091                    cx,
 8092                );
 8093            }
 8094
 8095            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8096                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8097            };
 8098            self.clear_row_highlights::<EditPredictionPreview>();
 8099            self.update_visible_edit_prediction(window, cx);
 8100            cx.notify();
 8101        }
 8102    }
 8103
 8104    fn update_visible_edit_prediction(
 8105        &mut self,
 8106        _window: &mut Window,
 8107        cx: &mut Context<Self>,
 8108    ) -> Option<()> {
 8109        if DisableAiSettings::get_global(cx).disable_ai {
 8110            return None;
 8111        }
 8112
 8113        if self.ime_transaction.is_some() {
 8114            self.discard_edit_prediction(false, cx);
 8115            return None;
 8116        }
 8117
 8118        let selection = self.selections.newest_anchor();
 8119        let cursor = selection.head();
 8120        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8121        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8122        let excerpt_id = cursor.excerpt_id;
 8123
 8124        let show_in_menu = self.show_edit_predictions_in_menu();
 8125        let completions_menu_has_precedence = !show_in_menu
 8126            && (self.context_menu.borrow().is_some()
 8127                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8128
 8129        if completions_menu_has_precedence
 8130            || !offset_selection.is_empty()
 8131            || self
 8132                .active_edit_prediction
 8133                .as_ref()
 8134                .is_some_and(|completion| {
 8135                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8136                        return false;
 8137                    };
 8138                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8139                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8140                    !invalidation_range.contains(&offset_selection.head())
 8141                })
 8142        {
 8143            self.discard_edit_prediction(false, cx);
 8144            return None;
 8145        }
 8146
 8147        self.take_active_edit_prediction(cx);
 8148        let Some(provider) = self.edit_prediction_provider() else {
 8149            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8150            return None;
 8151        };
 8152
 8153        let (buffer, cursor_buffer_position) =
 8154            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8155
 8156        self.edit_prediction_settings =
 8157            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8158
 8159        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8160
 8161        if self.edit_prediction_indent_conflict {
 8162            let cursor_point = cursor.to_point(&multibuffer);
 8163            let mut suggested_indent = None;
 8164            multibuffer.suggested_indents_callback(
 8165                cursor_point.row..cursor_point.row + 1,
 8166                |_, indent| {
 8167                    suggested_indent = Some(indent);
 8168                    ControlFlow::Break(())
 8169                },
 8170                cx,
 8171            );
 8172
 8173            if let Some(indent) = suggested_indent
 8174                && indent.len == cursor_point.column
 8175            {
 8176                self.edit_prediction_indent_conflict = false;
 8177            }
 8178        }
 8179
 8180        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8181
 8182        let (completion_id, edits, edit_preview) = match edit_prediction {
 8183            edit_prediction_types::EditPrediction::Local {
 8184                id,
 8185                edits,
 8186                edit_preview,
 8187            } => (id, edits, edit_preview),
 8188            edit_prediction_types::EditPrediction::Jump {
 8189                id,
 8190                snapshot,
 8191                target,
 8192            } => {
 8193                self.stale_edit_prediction_in_menu = None;
 8194                self.active_edit_prediction = Some(EditPredictionState {
 8195                    inlay_ids: vec![],
 8196                    completion: EditPrediction::MoveOutside { snapshot, target },
 8197                    completion_id: id,
 8198                    invalidation_range: None,
 8199                });
 8200                cx.notify();
 8201                return Some(());
 8202            }
 8203        };
 8204
 8205        let edits = edits
 8206            .into_iter()
 8207            .flat_map(|(range, new_text)| {
 8208                Some((
 8209                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8210                    new_text,
 8211                ))
 8212            })
 8213            .collect::<Vec<_>>();
 8214        if edits.is_empty() {
 8215            return None;
 8216        }
 8217
 8218        let first_edit_start = edits.first().unwrap().0.start;
 8219        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8220        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8221
 8222        let last_edit_end = edits.last().unwrap().0.end;
 8223        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8224        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8225
 8226        let cursor_row = cursor.to_point(&multibuffer).row;
 8227
 8228        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8229
 8230        let mut inlay_ids = Vec::new();
 8231        let invalidation_row_range;
 8232        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8233            Some(cursor_row..edit_end_row)
 8234        } else if cursor_row > edit_end_row {
 8235            Some(edit_start_row..cursor_row)
 8236        } else {
 8237            None
 8238        };
 8239        let supports_jump = self
 8240            .edit_prediction_provider
 8241            .as_ref()
 8242            .map(|provider| provider.provider.supports_jump_to_edit())
 8243            .unwrap_or(true);
 8244
 8245        let is_move = supports_jump
 8246            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8247        let completion = if is_move {
 8248            invalidation_row_range =
 8249                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8250            let target = first_edit_start;
 8251            EditPrediction::MoveWithin { target, snapshot }
 8252        } else {
 8253            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8254                && !self.edit_predictions_hidden_for_vim_mode;
 8255
 8256            if show_completions_in_buffer {
 8257                if let Some(provider) = &self.edit_prediction_provider {
 8258                    provider.provider.did_show(cx);
 8259                }
 8260                if edits
 8261                    .iter()
 8262                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8263                {
 8264                    let mut inlays = Vec::new();
 8265                    for (range, new_text) in &edits {
 8266                        let inlay = Inlay::edit_prediction(
 8267                            post_inc(&mut self.next_inlay_id),
 8268                            range.start,
 8269                            new_text.as_ref(),
 8270                        );
 8271                        inlay_ids.push(inlay.id);
 8272                        inlays.push(inlay);
 8273                    }
 8274
 8275                    self.splice_inlays(&[], inlays, cx);
 8276                } else {
 8277                    let background_color = cx.theme().status().deleted_background;
 8278                    self.highlight_text::<EditPredictionHighlight>(
 8279                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8280                        HighlightStyle {
 8281                            background_color: Some(background_color),
 8282                            ..Default::default()
 8283                        },
 8284                        cx,
 8285                    );
 8286                }
 8287            }
 8288
 8289            invalidation_row_range = edit_start_row..edit_end_row;
 8290
 8291            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8292                if provider.show_tab_accept_marker() {
 8293                    EditDisplayMode::TabAccept
 8294                } else {
 8295                    EditDisplayMode::Inline
 8296                }
 8297            } else {
 8298                EditDisplayMode::DiffPopover
 8299            };
 8300
 8301            EditPrediction::Edit {
 8302                edits,
 8303                edit_preview,
 8304                display_mode,
 8305                snapshot,
 8306            }
 8307        };
 8308
 8309        let invalidation_range = multibuffer
 8310            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8311            ..multibuffer.anchor_after(Point::new(
 8312                invalidation_row_range.end,
 8313                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8314            ));
 8315
 8316        self.stale_edit_prediction_in_menu = None;
 8317        self.active_edit_prediction = Some(EditPredictionState {
 8318            inlay_ids,
 8319            completion,
 8320            completion_id,
 8321            invalidation_range: Some(invalidation_range),
 8322        });
 8323
 8324        cx.notify();
 8325
 8326        Some(())
 8327    }
 8328
 8329    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8330        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8331    }
 8332
 8333    fn clear_tasks(&mut self) {
 8334        self.tasks.clear()
 8335    }
 8336
 8337    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8338        if self.tasks.insert(key, value).is_some() {
 8339            // This case should hopefully be rare, but just in case...
 8340            log::error!(
 8341                "multiple different run targets found on a single line, only the last target will be rendered"
 8342            )
 8343        }
 8344    }
 8345
 8346    /// Get all display points of breakpoints that will be rendered within editor
 8347    ///
 8348    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8349    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8350    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8351    fn active_breakpoints(
 8352        &self,
 8353        range: Range<DisplayRow>,
 8354        window: &mut Window,
 8355        cx: &mut Context<Self>,
 8356    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8357        let mut breakpoint_display_points = HashMap::default();
 8358
 8359        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8360            return breakpoint_display_points;
 8361        };
 8362
 8363        let snapshot = self.snapshot(window, cx);
 8364
 8365        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8366        let Some(project) = self.project() else {
 8367            return breakpoint_display_points;
 8368        };
 8369
 8370        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8371            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8372
 8373        for (buffer_snapshot, range, excerpt_id) in
 8374            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8375        {
 8376            let Some(buffer) = project
 8377                .read(cx)
 8378                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8379            else {
 8380                continue;
 8381            };
 8382            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8383                &buffer,
 8384                Some(
 8385                    buffer_snapshot.anchor_before(range.start)
 8386                        ..buffer_snapshot.anchor_after(range.end),
 8387                ),
 8388                buffer_snapshot,
 8389                cx,
 8390            );
 8391            for (breakpoint, state) in breakpoints {
 8392                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8393                let position = multi_buffer_anchor
 8394                    .to_point(&multi_buffer_snapshot)
 8395                    .to_display_point(&snapshot);
 8396
 8397                breakpoint_display_points.insert(
 8398                    position.row(),
 8399                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8400                );
 8401            }
 8402        }
 8403
 8404        breakpoint_display_points
 8405    }
 8406
 8407    fn breakpoint_context_menu(
 8408        &self,
 8409        anchor: Anchor,
 8410        window: &mut Window,
 8411        cx: &mut Context<Self>,
 8412    ) -> Entity<ui::ContextMenu> {
 8413        let weak_editor = cx.weak_entity();
 8414        let focus_handle = self.focus_handle(cx);
 8415
 8416        let row = self
 8417            .buffer
 8418            .read(cx)
 8419            .snapshot(cx)
 8420            .summary_for_anchor::<Point>(&anchor)
 8421            .row;
 8422
 8423        let breakpoint = self
 8424            .breakpoint_at_row(row, window, cx)
 8425            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8426
 8427        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8428            "Edit Log Breakpoint"
 8429        } else {
 8430            "Set Log Breakpoint"
 8431        };
 8432
 8433        let condition_breakpoint_msg = if breakpoint
 8434            .as_ref()
 8435            .is_some_and(|bp| bp.1.condition.is_some())
 8436        {
 8437            "Edit Condition Breakpoint"
 8438        } else {
 8439            "Set Condition Breakpoint"
 8440        };
 8441
 8442        let hit_condition_breakpoint_msg = if breakpoint
 8443            .as_ref()
 8444            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8445        {
 8446            "Edit Hit Condition Breakpoint"
 8447        } else {
 8448            "Set Hit Condition Breakpoint"
 8449        };
 8450
 8451        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8452            "Unset Breakpoint"
 8453        } else {
 8454            "Set Breakpoint"
 8455        };
 8456
 8457        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8458
 8459        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8460            BreakpointState::Enabled => Some("Disable"),
 8461            BreakpointState::Disabled => Some("Enable"),
 8462        });
 8463
 8464        let (anchor, breakpoint) =
 8465            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8466
 8467        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8468            menu.on_blur_subscription(Subscription::new(|| {}))
 8469                .context(focus_handle)
 8470                .when(run_to_cursor, |this| {
 8471                    let weak_editor = weak_editor.clone();
 8472                    this.entry("Run to cursor", None, move |window, cx| {
 8473                        weak_editor
 8474                            .update(cx, |editor, cx| {
 8475                                editor.change_selections(
 8476                                    SelectionEffects::no_scroll(),
 8477                                    window,
 8478                                    cx,
 8479                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8480                                );
 8481                            })
 8482                            .ok();
 8483
 8484                        window.dispatch_action(Box::new(RunToCursor), cx);
 8485                    })
 8486                    .separator()
 8487                })
 8488                .when_some(toggle_state_msg, |this, msg| {
 8489                    this.entry(msg, None, {
 8490                        let weak_editor = weak_editor.clone();
 8491                        let breakpoint = breakpoint.clone();
 8492                        move |_window, cx| {
 8493                            weak_editor
 8494                                .update(cx, |this, cx| {
 8495                                    this.edit_breakpoint_at_anchor(
 8496                                        anchor,
 8497                                        breakpoint.as_ref().clone(),
 8498                                        BreakpointEditAction::InvertState,
 8499                                        cx,
 8500                                    );
 8501                                })
 8502                                .log_err();
 8503                        }
 8504                    })
 8505                })
 8506                .entry(set_breakpoint_msg, None, {
 8507                    let weak_editor = weak_editor.clone();
 8508                    let breakpoint = breakpoint.clone();
 8509                    move |_window, cx| {
 8510                        weak_editor
 8511                            .update(cx, |this, cx| {
 8512                                this.edit_breakpoint_at_anchor(
 8513                                    anchor,
 8514                                    breakpoint.as_ref().clone(),
 8515                                    BreakpointEditAction::Toggle,
 8516                                    cx,
 8517                                );
 8518                            })
 8519                            .log_err();
 8520                    }
 8521                })
 8522                .entry(log_breakpoint_msg, None, {
 8523                    let breakpoint = breakpoint.clone();
 8524                    let weak_editor = weak_editor.clone();
 8525                    move |window, cx| {
 8526                        weak_editor
 8527                            .update(cx, |this, cx| {
 8528                                this.add_edit_breakpoint_block(
 8529                                    anchor,
 8530                                    breakpoint.as_ref(),
 8531                                    BreakpointPromptEditAction::Log,
 8532                                    window,
 8533                                    cx,
 8534                                );
 8535                            })
 8536                            .log_err();
 8537                    }
 8538                })
 8539                .entry(condition_breakpoint_msg, None, {
 8540                    let breakpoint = breakpoint.clone();
 8541                    let weak_editor = weak_editor.clone();
 8542                    move |window, cx| {
 8543                        weak_editor
 8544                            .update(cx, |this, cx| {
 8545                                this.add_edit_breakpoint_block(
 8546                                    anchor,
 8547                                    breakpoint.as_ref(),
 8548                                    BreakpointPromptEditAction::Condition,
 8549                                    window,
 8550                                    cx,
 8551                                );
 8552                            })
 8553                            .log_err();
 8554                    }
 8555                })
 8556                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8557                    weak_editor
 8558                        .update(cx, |this, cx| {
 8559                            this.add_edit_breakpoint_block(
 8560                                anchor,
 8561                                breakpoint.as_ref(),
 8562                                BreakpointPromptEditAction::HitCondition,
 8563                                window,
 8564                                cx,
 8565                            );
 8566                        })
 8567                        .log_err();
 8568                })
 8569        })
 8570    }
 8571
 8572    fn render_breakpoint(
 8573        &self,
 8574        position: Anchor,
 8575        row: DisplayRow,
 8576        breakpoint: &Breakpoint,
 8577        state: Option<BreakpointSessionState>,
 8578        cx: &mut Context<Self>,
 8579    ) -> IconButton {
 8580        let is_rejected = state.is_some_and(|s| !s.verified);
 8581        // Is it a breakpoint that shows up when hovering over gutter?
 8582        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8583            (false, false),
 8584            |PhantomBreakpointIndicator {
 8585                 is_active,
 8586                 display_row,
 8587                 collides_with_existing_breakpoint,
 8588             }| {
 8589                (
 8590                    is_active && display_row == row,
 8591                    collides_with_existing_breakpoint,
 8592                )
 8593            },
 8594        );
 8595
 8596        let (color, icon) = {
 8597            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8598                (false, false) => ui::IconName::DebugBreakpoint,
 8599                (true, false) => ui::IconName::DebugLogBreakpoint,
 8600                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8601                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8602            };
 8603
 8604            let color = cx.theme().colors();
 8605
 8606            let color = if is_phantom {
 8607                if collides_with_existing {
 8608                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8609                } else {
 8610                    Color::Hint
 8611                }
 8612            } else if is_rejected {
 8613                Color::Disabled
 8614            } else {
 8615                Color::Debugger
 8616            };
 8617
 8618            (color, icon)
 8619        };
 8620
 8621        let breakpoint = Arc::from(breakpoint.clone());
 8622
 8623        let alt_as_text = gpui::Keystroke {
 8624            modifiers: Modifiers::secondary_key(),
 8625            ..Default::default()
 8626        };
 8627        let primary_action_text = if breakpoint.is_disabled() {
 8628            "Enable breakpoint"
 8629        } else if is_phantom && !collides_with_existing {
 8630            "Set breakpoint"
 8631        } else {
 8632            "Unset breakpoint"
 8633        };
 8634        let focus_handle = self.focus_handle.clone();
 8635
 8636        let meta = if is_rejected {
 8637            SharedString::from("No executable code is associated with this line.")
 8638        } else if collides_with_existing && !breakpoint.is_disabled() {
 8639            SharedString::from(format!(
 8640                "{alt_as_text}-click to disable,\nright-click for more options."
 8641            ))
 8642        } else {
 8643            SharedString::from("Right-click for more options.")
 8644        };
 8645        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8646            .icon_size(IconSize::XSmall)
 8647            .size(ui::ButtonSize::None)
 8648            .when(is_rejected, |this| {
 8649                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8650            })
 8651            .icon_color(color)
 8652            .style(ButtonStyle::Transparent)
 8653            .on_click(cx.listener({
 8654                move |editor, event: &ClickEvent, window, cx| {
 8655                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8656                        BreakpointEditAction::InvertState
 8657                    } else {
 8658                        BreakpointEditAction::Toggle
 8659                    };
 8660
 8661                    window.focus(&editor.focus_handle(cx));
 8662                    editor.edit_breakpoint_at_anchor(
 8663                        position,
 8664                        breakpoint.as_ref().clone(),
 8665                        edit_action,
 8666                        cx,
 8667                    );
 8668                }
 8669            }))
 8670            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8671                editor.set_breakpoint_context_menu(
 8672                    row,
 8673                    Some(position),
 8674                    event.position(),
 8675                    window,
 8676                    cx,
 8677                );
 8678            }))
 8679            .tooltip(move |_window, cx| {
 8680                Tooltip::with_meta_in(
 8681                    primary_action_text,
 8682                    Some(&ToggleBreakpoint),
 8683                    meta.clone(),
 8684                    &focus_handle,
 8685                    cx,
 8686                )
 8687            })
 8688    }
 8689
 8690    fn build_tasks_context(
 8691        project: &Entity<Project>,
 8692        buffer: &Entity<Buffer>,
 8693        buffer_row: u32,
 8694        tasks: &Arc<RunnableTasks>,
 8695        cx: &mut Context<Self>,
 8696    ) -> Task<Option<task::TaskContext>> {
 8697        let position = Point::new(buffer_row, tasks.column);
 8698        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8699        let location = Location {
 8700            buffer: buffer.clone(),
 8701            range: range_start..range_start,
 8702        };
 8703        // Fill in the environmental variables from the tree-sitter captures
 8704        let mut captured_task_variables = TaskVariables::default();
 8705        for (capture_name, value) in tasks.extra_variables.clone() {
 8706            captured_task_variables.insert(
 8707                task::VariableName::Custom(capture_name.into()),
 8708                value.clone(),
 8709            );
 8710        }
 8711        project.update(cx, |project, cx| {
 8712            project.task_store().update(cx, |task_store, cx| {
 8713                task_store.task_context_for_location(captured_task_variables, location, cx)
 8714            })
 8715        })
 8716    }
 8717
 8718    pub fn spawn_nearest_task(
 8719        &mut self,
 8720        action: &SpawnNearestTask,
 8721        window: &mut Window,
 8722        cx: &mut Context<Self>,
 8723    ) {
 8724        let Some((workspace, _)) = self.workspace.clone() else {
 8725            return;
 8726        };
 8727        let Some(project) = self.project.clone() else {
 8728            return;
 8729        };
 8730
 8731        // Try to find a closest, enclosing node using tree-sitter that has a task
 8732        let Some((buffer, buffer_row, tasks)) = self
 8733            .find_enclosing_node_task(cx)
 8734            // Or find the task that's closest in row-distance.
 8735            .or_else(|| self.find_closest_task(cx))
 8736        else {
 8737            return;
 8738        };
 8739
 8740        let reveal_strategy = action.reveal;
 8741        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8742        cx.spawn_in(window, async move |_, cx| {
 8743            let context = task_context.await?;
 8744            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8745
 8746            let resolved = &mut resolved_task.resolved;
 8747            resolved.reveal = reveal_strategy;
 8748
 8749            workspace
 8750                .update_in(cx, |workspace, window, cx| {
 8751                    workspace.schedule_resolved_task(
 8752                        task_source_kind,
 8753                        resolved_task,
 8754                        false,
 8755                        window,
 8756                        cx,
 8757                    );
 8758                })
 8759                .ok()
 8760        })
 8761        .detach();
 8762    }
 8763
 8764    fn find_closest_task(
 8765        &mut self,
 8766        cx: &mut Context<Self>,
 8767    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8768        let cursor_row = self
 8769            .selections
 8770            .newest_adjusted(&self.display_snapshot(cx))
 8771            .head()
 8772            .row;
 8773
 8774        let ((buffer_id, row), tasks) = self
 8775            .tasks
 8776            .iter()
 8777            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8778
 8779        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8780        let tasks = Arc::new(tasks.to_owned());
 8781        Some((buffer, *row, tasks))
 8782    }
 8783
 8784    fn find_enclosing_node_task(
 8785        &mut self,
 8786        cx: &mut Context<Self>,
 8787    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8788        let snapshot = self.buffer.read(cx).snapshot(cx);
 8789        let offset = self
 8790            .selections
 8791            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8792            .head();
 8793        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8794        let offset = excerpt.map_offset_to_buffer(offset);
 8795        let buffer_id = excerpt.buffer().remote_id();
 8796
 8797        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8798        let mut cursor = layer.node().walk();
 8799
 8800        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8801            if cursor.node().end_byte() == offset.0 {
 8802                cursor.goto_next_sibling();
 8803            }
 8804        }
 8805
 8806        // Ascend to the smallest ancestor that contains the range and has a task.
 8807        loop {
 8808            let node = cursor.node();
 8809            let node_range = node.byte_range();
 8810            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8811
 8812            // Check if this node contains our offset
 8813            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8814                // If it contains offset, check for task
 8815                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8816                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8817                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8818                }
 8819            }
 8820
 8821            if !cursor.goto_parent() {
 8822                break;
 8823            }
 8824        }
 8825        None
 8826    }
 8827
 8828    fn render_run_indicator(
 8829        &self,
 8830        _style: &EditorStyle,
 8831        is_active: bool,
 8832        row: DisplayRow,
 8833        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8834        cx: &mut Context<Self>,
 8835    ) -> IconButton {
 8836        let color = Color::Muted;
 8837        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8838
 8839        IconButton::new(
 8840            ("run_indicator", row.0 as usize),
 8841            ui::IconName::PlayOutlined,
 8842        )
 8843        .shape(ui::IconButtonShape::Square)
 8844        .icon_size(IconSize::XSmall)
 8845        .icon_color(color)
 8846        .toggle_state(is_active)
 8847        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8848            let quick_launch = match e {
 8849                ClickEvent::Keyboard(_) => true,
 8850                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8851            };
 8852
 8853            window.focus(&editor.focus_handle(cx));
 8854            editor.toggle_code_actions(
 8855                &ToggleCodeActions {
 8856                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8857                    quick_launch,
 8858                },
 8859                window,
 8860                cx,
 8861            );
 8862        }))
 8863        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8864            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8865        }))
 8866    }
 8867
 8868    pub fn context_menu_visible(&self) -> bool {
 8869        !self.edit_prediction_preview_is_active()
 8870            && self
 8871                .context_menu
 8872                .borrow()
 8873                .as_ref()
 8874                .is_some_and(|menu| menu.visible())
 8875    }
 8876
 8877    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8878        self.context_menu
 8879            .borrow()
 8880            .as_ref()
 8881            .map(|menu| menu.origin())
 8882    }
 8883
 8884    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8885        self.context_menu_options = Some(options);
 8886    }
 8887
 8888    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8889    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8890
 8891    fn render_edit_prediction_popover(
 8892        &mut self,
 8893        text_bounds: &Bounds<Pixels>,
 8894        content_origin: gpui::Point<Pixels>,
 8895        right_margin: Pixels,
 8896        editor_snapshot: &EditorSnapshot,
 8897        visible_row_range: Range<DisplayRow>,
 8898        scroll_top: ScrollOffset,
 8899        scroll_bottom: ScrollOffset,
 8900        line_layouts: &[LineWithInvisibles],
 8901        line_height: Pixels,
 8902        scroll_position: gpui::Point<ScrollOffset>,
 8903        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8904        newest_selection_head: Option<DisplayPoint>,
 8905        editor_width: Pixels,
 8906        style: &EditorStyle,
 8907        window: &mut Window,
 8908        cx: &mut App,
 8909    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8910        if self.mode().is_minimap() {
 8911            return None;
 8912        }
 8913        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8914
 8915        if self.edit_prediction_visible_in_cursor_popover(true) {
 8916            return None;
 8917        }
 8918
 8919        match &active_edit_prediction.completion {
 8920            EditPrediction::MoveWithin { target, .. } => {
 8921                let target_display_point = target.to_display_point(editor_snapshot);
 8922
 8923                if self.edit_prediction_requires_modifier() {
 8924                    if !self.edit_prediction_preview_is_active() {
 8925                        return None;
 8926                    }
 8927
 8928                    self.render_edit_prediction_modifier_jump_popover(
 8929                        text_bounds,
 8930                        content_origin,
 8931                        visible_row_range,
 8932                        line_layouts,
 8933                        line_height,
 8934                        scroll_pixel_position,
 8935                        newest_selection_head,
 8936                        target_display_point,
 8937                        window,
 8938                        cx,
 8939                    )
 8940                } else {
 8941                    self.render_edit_prediction_eager_jump_popover(
 8942                        text_bounds,
 8943                        content_origin,
 8944                        editor_snapshot,
 8945                        visible_row_range,
 8946                        scroll_top,
 8947                        scroll_bottom,
 8948                        line_height,
 8949                        scroll_pixel_position,
 8950                        target_display_point,
 8951                        editor_width,
 8952                        window,
 8953                        cx,
 8954                    )
 8955                }
 8956            }
 8957            EditPrediction::Edit {
 8958                display_mode: EditDisplayMode::Inline,
 8959                ..
 8960            } => None,
 8961            EditPrediction::Edit {
 8962                display_mode: EditDisplayMode::TabAccept,
 8963                edits,
 8964                ..
 8965            } => {
 8966                let range = &edits.first()?.0;
 8967                let target_display_point = range.end.to_display_point(editor_snapshot);
 8968
 8969                self.render_edit_prediction_end_of_line_popover(
 8970                    "Accept",
 8971                    editor_snapshot,
 8972                    visible_row_range,
 8973                    target_display_point,
 8974                    line_height,
 8975                    scroll_pixel_position,
 8976                    content_origin,
 8977                    editor_width,
 8978                    window,
 8979                    cx,
 8980                )
 8981            }
 8982            EditPrediction::Edit {
 8983                edits,
 8984                edit_preview,
 8985                display_mode: EditDisplayMode::DiffPopover,
 8986                snapshot,
 8987            } => self.render_edit_prediction_diff_popover(
 8988                text_bounds,
 8989                content_origin,
 8990                right_margin,
 8991                editor_snapshot,
 8992                visible_row_range,
 8993                line_layouts,
 8994                line_height,
 8995                scroll_position,
 8996                scroll_pixel_position,
 8997                newest_selection_head,
 8998                editor_width,
 8999                style,
 9000                edits,
 9001                edit_preview,
 9002                snapshot,
 9003                window,
 9004                cx,
 9005            ),
 9006            EditPrediction::MoveOutside { snapshot, .. } => {
 9007                let mut element = self
 9008                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9009                    .into_any();
 9010
 9011                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9012                let origin_x = text_bounds.size.width - size.width - px(30.);
 9013                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9014                element.prepaint_at(origin, window, cx);
 9015
 9016                Some((element, origin))
 9017            }
 9018        }
 9019    }
 9020
 9021    fn render_edit_prediction_modifier_jump_popover(
 9022        &mut self,
 9023        text_bounds: &Bounds<Pixels>,
 9024        content_origin: gpui::Point<Pixels>,
 9025        visible_row_range: Range<DisplayRow>,
 9026        line_layouts: &[LineWithInvisibles],
 9027        line_height: Pixels,
 9028        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9029        newest_selection_head: Option<DisplayPoint>,
 9030        target_display_point: DisplayPoint,
 9031        window: &mut Window,
 9032        cx: &mut App,
 9033    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9034        let scrolled_content_origin =
 9035            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9036
 9037        const SCROLL_PADDING_Y: Pixels = px(12.);
 9038
 9039        if target_display_point.row() < visible_row_range.start {
 9040            return self.render_edit_prediction_scroll_popover(
 9041                |_| SCROLL_PADDING_Y,
 9042                IconName::ArrowUp,
 9043                visible_row_range,
 9044                line_layouts,
 9045                newest_selection_head,
 9046                scrolled_content_origin,
 9047                window,
 9048                cx,
 9049            );
 9050        } else if target_display_point.row() >= visible_row_range.end {
 9051            return self.render_edit_prediction_scroll_popover(
 9052                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9053                IconName::ArrowDown,
 9054                visible_row_range,
 9055                line_layouts,
 9056                newest_selection_head,
 9057                scrolled_content_origin,
 9058                window,
 9059                cx,
 9060            );
 9061        }
 9062
 9063        const POLE_WIDTH: Pixels = px(2.);
 9064
 9065        let line_layout =
 9066            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9067        let target_column = target_display_point.column() as usize;
 9068
 9069        let target_x = line_layout.x_for_index(target_column);
 9070        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9071            - scroll_pixel_position.y;
 9072
 9073        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9074
 9075        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9076        border_color.l += 0.001;
 9077
 9078        let mut element = v_flex()
 9079            .items_end()
 9080            .when(flag_on_right, |el| el.items_start())
 9081            .child(if flag_on_right {
 9082                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9083                    .rounded_bl(px(0.))
 9084                    .rounded_tl(px(0.))
 9085                    .border_l_2()
 9086                    .border_color(border_color)
 9087            } else {
 9088                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9089                    .rounded_br(px(0.))
 9090                    .rounded_tr(px(0.))
 9091                    .border_r_2()
 9092                    .border_color(border_color)
 9093            })
 9094            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9095            .into_any();
 9096
 9097        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9098
 9099        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9100            - point(
 9101                if flag_on_right {
 9102                    POLE_WIDTH
 9103                } else {
 9104                    size.width - POLE_WIDTH
 9105                },
 9106                size.height - line_height,
 9107            );
 9108
 9109        origin.x = origin.x.max(content_origin.x);
 9110
 9111        element.prepaint_at(origin, window, cx);
 9112
 9113        Some((element, origin))
 9114    }
 9115
 9116    fn render_edit_prediction_scroll_popover(
 9117        &mut self,
 9118        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9119        scroll_icon: IconName,
 9120        visible_row_range: Range<DisplayRow>,
 9121        line_layouts: &[LineWithInvisibles],
 9122        newest_selection_head: Option<DisplayPoint>,
 9123        scrolled_content_origin: gpui::Point<Pixels>,
 9124        window: &mut Window,
 9125        cx: &mut App,
 9126    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9127        let mut element = self
 9128            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9129            .into_any();
 9130
 9131        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9132
 9133        let cursor = newest_selection_head?;
 9134        let cursor_row_layout =
 9135            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9136        let cursor_column = cursor.column() as usize;
 9137
 9138        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9139
 9140        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9141
 9142        element.prepaint_at(origin, window, cx);
 9143        Some((element, origin))
 9144    }
 9145
 9146    fn render_edit_prediction_eager_jump_popover(
 9147        &mut self,
 9148        text_bounds: &Bounds<Pixels>,
 9149        content_origin: gpui::Point<Pixels>,
 9150        editor_snapshot: &EditorSnapshot,
 9151        visible_row_range: Range<DisplayRow>,
 9152        scroll_top: ScrollOffset,
 9153        scroll_bottom: ScrollOffset,
 9154        line_height: Pixels,
 9155        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9156        target_display_point: DisplayPoint,
 9157        editor_width: Pixels,
 9158        window: &mut Window,
 9159        cx: &mut App,
 9160    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9161        if target_display_point.row().as_f64() < scroll_top {
 9162            let mut element = self
 9163                .render_edit_prediction_line_popover(
 9164                    "Jump to Edit",
 9165                    Some(IconName::ArrowUp),
 9166                    window,
 9167                    cx,
 9168                )
 9169                .into_any();
 9170
 9171            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9172            let offset = point(
 9173                (text_bounds.size.width - size.width) / 2.,
 9174                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9175            );
 9176
 9177            let origin = text_bounds.origin + offset;
 9178            element.prepaint_at(origin, window, cx);
 9179            Some((element, origin))
 9180        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9181            let mut element = self
 9182                .render_edit_prediction_line_popover(
 9183                    "Jump to Edit",
 9184                    Some(IconName::ArrowDown),
 9185                    window,
 9186                    cx,
 9187                )
 9188                .into_any();
 9189
 9190            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9191            let offset = point(
 9192                (text_bounds.size.width - size.width) / 2.,
 9193                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9194            );
 9195
 9196            let origin = text_bounds.origin + offset;
 9197            element.prepaint_at(origin, window, cx);
 9198            Some((element, origin))
 9199        } else {
 9200            self.render_edit_prediction_end_of_line_popover(
 9201                "Jump to Edit",
 9202                editor_snapshot,
 9203                visible_row_range,
 9204                target_display_point,
 9205                line_height,
 9206                scroll_pixel_position,
 9207                content_origin,
 9208                editor_width,
 9209                window,
 9210                cx,
 9211            )
 9212        }
 9213    }
 9214
 9215    fn render_edit_prediction_end_of_line_popover(
 9216        self: &mut Editor,
 9217        label: &'static str,
 9218        editor_snapshot: &EditorSnapshot,
 9219        visible_row_range: Range<DisplayRow>,
 9220        target_display_point: DisplayPoint,
 9221        line_height: Pixels,
 9222        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9223        content_origin: gpui::Point<Pixels>,
 9224        editor_width: Pixels,
 9225        window: &mut Window,
 9226        cx: &mut App,
 9227    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9228        let target_line_end = DisplayPoint::new(
 9229            target_display_point.row(),
 9230            editor_snapshot.line_len(target_display_point.row()),
 9231        );
 9232
 9233        let mut element = self
 9234            .render_edit_prediction_line_popover(label, None, window, cx)
 9235            .into_any();
 9236
 9237        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9238
 9239        let line_origin =
 9240            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9241
 9242        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9243        let mut origin = start_point
 9244            + line_origin
 9245            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9246        origin.x = origin.x.max(content_origin.x);
 9247
 9248        let max_x = content_origin.x + editor_width - size.width;
 9249
 9250        if origin.x > max_x {
 9251            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9252
 9253            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9254                origin.y += offset;
 9255                IconName::ArrowUp
 9256            } else {
 9257                origin.y -= offset;
 9258                IconName::ArrowDown
 9259            };
 9260
 9261            element = self
 9262                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9263                .into_any();
 9264
 9265            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9266
 9267            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9268        }
 9269
 9270        element.prepaint_at(origin, window, cx);
 9271        Some((element, origin))
 9272    }
 9273
 9274    fn render_edit_prediction_diff_popover(
 9275        self: &Editor,
 9276        text_bounds: &Bounds<Pixels>,
 9277        content_origin: gpui::Point<Pixels>,
 9278        right_margin: Pixels,
 9279        editor_snapshot: &EditorSnapshot,
 9280        visible_row_range: Range<DisplayRow>,
 9281        line_layouts: &[LineWithInvisibles],
 9282        line_height: Pixels,
 9283        scroll_position: gpui::Point<ScrollOffset>,
 9284        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9285        newest_selection_head: Option<DisplayPoint>,
 9286        editor_width: Pixels,
 9287        style: &EditorStyle,
 9288        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9289        edit_preview: &Option<language::EditPreview>,
 9290        snapshot: &language::BufferSnapshot,
 9291        window: &mut Window,
 9292        cx: &mut App,
 9293    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9294        let edit_start = edits
 9295            .first()
 9296            .unwrap()
 9297            .0
 9298            .start
 9299            .to_display_point(editor_snapshot);
 9300        let edit_end = edits
 9301            .last()
 9302            .unwrap()
 9303            .0
 9304            .end
 9305            .to_display_point(editor_snapshot);
 9306
 9307        let is_visible = visible_row_range.contains(&edit_start.row())
 9308            || visible_row_range.contains(&edit_end.row());
 9309        if !is_visible {
 9310            return None;
 9311        }
 9312
 9313        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9314            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9315        } else {
 9316            // Fallback for providers without edit_preview
 9317            crate::edit_prediction_fallback_text(edits, cx)
 9318        };
 9319
 9320        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9321        let line_count = highlighted_edits.text.lines().count();
 9322
 9323        const BORDER_WIDTH: Pixels = px(1.);
 9324
 9325        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9326        let has_keybind = keybind.is_some();
 9327
 9328        let mut element = h_flex()
 9329            .items_start()
 9330            .child(
 9331                h_flex()
 9332                    .bg(cx.theme().colors().editor_background)
 9333                    .border(BORDER_WIDTH)
 9334                    .shadow_xs()
 9335                    .border_color(cx.theme().colors().border)
 9336                    .rounded_l_lg()
 9337                    .when(line_count > 1, |el| el.rounded_br_lg())
 9338                    .pr_1()
 9339                    .child(styled_text),
 9340            )
 9341            .child(
 9342                h_flex()
 9343                    .h(line_height + BORDER_WIDTH * 2.)
 9344                    .px_1p5()
 9345                    .gap_1()
 9346                    // Workaround: For some reason, there's a gap if we don't do this
 9347                    .ml(-BORDER_WIDTH)
 9348                    .shadow(vec![gpui::BoxShadow {
 9349                        color: gpui::black().opacity(0.05),
 9350                        offset: point(px(1.), px(1.)),
 9351                        blur_radius: px(2.),
 9352                        spread_radius: px(0.),
 9353                    }])
 9354                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9355                    .border(BORDER_WIDTH)
 9356                    .border_color(cx.theme().colors().border)
 9357                    .rounded_r_lg()
 9358                    .id("edit_prediction_diff_popover_keybind")
 9359                    .when(!has_keybind, |el| {
 9360                        let status_colors = cx.theme().status();
 9361
 9362                        el.bg(status_colors.error_background)
 9363                            .border_color(status_colors.error.opacity(0.6))
 9364                            .child(Icon::new(IconName::Info).color(Color::Error))
 9365                            .cursor_default()
 9366                            .hoverable_tooltip(move |_window, cx| {
 9367                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9368                            })
 9369                    })
 9370                    .children(keybind),
 9371            )
 9372            .into_any();
 9373
 9374        let longest_row =
 9375            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9376        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9377            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9378        } else {
 9379            layout_line(
 9380                longest_row,
 9381                editor_snapshot,
 9382                style,
 9383                editor_width,
 9384                |_| false,
 9385                window,
 9386                cx,
 9387            )
 9388            .width
 9389        };
 9390
 9391        let viewport_bounds =
 9392            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9393                right: -right_margin,
 9394                ..Default::default()
 9395            });
 9396
 9397        let x_after_longest = Pixels::from(
 9398            ScrollPixelOffset::from(
 9399                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9400            ) - scroll_pixel_position.x,
 9401        );
 9402
 9403        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9404
 9405        // Fully visible if it can be displayed within the window (allow overlapping other
 9406        // panes). However, this is only allowed if the popover starts within text_bounds.
 9407        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9408            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9409
 9410        let mut origin = if can_position_to_the_right {
 9411            point(
 9412                x_after_longest,
 9413                text_bounds.origin.y
 9414                    + Pixels::from(
 9415                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9416                            - scroll_pixel_position.y,
 9417                    ),
 9418            )
 9419        } else {
 9420            let cursor_row = newest_selection_head.map(|head| head.row());
 9421            let above_edit = edit_start
 9422                .row()
 9423                .0
 9424                .checked_sub(line_count as u32)
 9425                .map(DisplayRow);
 9426            let below_edit = Some(edit_end.row() + 1);
 9427            let above_cursor =
 9428                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9429            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9430
 9431            // Place the edit popover adjacent to the edit if there is a location
 9432            // available that is onscreen and does not obscure the cursor. Otherwise,
 9433            // place it adjacent to the cursor.
 9434            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9435                .into_iter()
 9436                .flatten()
 9437                .find(|&start_row| {
 9438                    let end_row = start_row + line_count as u32;
 9439                    visible_row_range.contains(&start_row)
 9440                        && visible_row_range.contains(&end_row)
 9441                        && cursor_row
 9442                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9443                })?;
 9444
 9445            content_origin
 9446                + point(
 9447                    Pixels::from(-scroll_pixel_position.x),
 9448                    Pixels::from(
 9449                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9450                    ),
 9451                )
 9452        };
 9453
 9454        origin.x -= BORDER_WIDTH;
 9455
 9456        window.defer_draw(element, origin, 1);
 9457
 9458        // Do not return an element, since it will already be drawn due to defer_draw.
 9459        None
 9460    }
 9461
 9462    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9463        px(30.)
 9464    }
 9465
 9466    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9467        if self.read_only(cx) {
 9468            cx.theme().players().read_only()
 9469        } else {
 9470            self.style.as_ref().unwrap().local_player
 9471        }
 9472    }
 9473
 9474    fn render_edit_prediction_accept_keybind(
 9475        &self,
 9476        window: &mut Window,
 9477        cx: &mut App,
 9478    ) -> Option<AnyElement> {
 9479        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9480        let accept_keystroke = accept_binding.keystroke()?;
 9481
 9482        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9483
 9484        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9485            Color::Accent
 9486        } else {
 9487            Color::Muted
 9488        };
 9489
 9490        h_flex()
 9491            .px_0p5()
 9492            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9493            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9494            .text_size(TextSize::XSmall.rems(cx))
 9495            .child(h_flex().children(ui::render_modifiers(
 9496                accept_keystroke.modifiers(),
 9497                PlatformStyle::platform(),
 9498                Some(modifiers_color),
 9499                Some(IconSize::XSmall.rems().into()),
 9500                true,
 9501            )))
 9502            .when(is_platform_style_mac, |parent| {
 9503                parent.child(accept_keystroke.key().to_string())
 9504            })
 9505            .when(!is_platform_style_mac, |parent| {
 9506                parent.child(
 9507                    Key::new(
 9508                        util::capitalize(accept_keystroke.key()),
 9509                        Some(Color::Default),
 9510                    )
 9511                    .size(Some(IconSize::XSmall.rems().into())),
 9512                )
 9513            })
 9514            .into_any()
 9515            .into()
 9516    }
 9517
 9518    fn render_edit_prediction_line_popover(
 9519        &self,
 9520        label: impl Into<SharedString>,
 9521        icon: Option<IconName>,
 9522        window: &mut Window,
 9523        cx: &mut App,
 9524    ) -> Stateful<Div> {
 9525        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9526
 9527        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9528        let has_keybind = keybind.is_some();
 9529
 9530        h_flex()
 9531            .id("ep-line-popover")
 9532            .py_0p5()
 9533            .pl_1()
 9534            .pr(padding_right)
 9535            .gap_1()
 9536            .rounded_md()
 9537            .border_1()
 9538            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9539            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9540            .shadow_xs()
 9541            .when(!has_keybind, |el| {
 9542                let status_colors = cx.theme().status();
 9543
 9544                el.bg(status_colors.error_background)
 9545                    .border_color(status_colors.error.opacity(0.6))
 9546                    .pl_2()
 9547                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9548                    .cursor_default()
 9549                    .hoverable_tooltip(move |_window, cx| {
 9550                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9551                    })
 9552            })
 9553            .children(keybind)
 9554            .child(
 9555                Label::new(label)
 9556                    .size(LabelSize::Small)
 9557                    .when(!has_keybind, |el| {
 9558                        el.color(cx.theme().status().error.into()).strikethrough()
 9559                    }),
 9560            )
 9561            .when(!has_keybind, |el| {
 9562                el.child(
 9563                    h_flex().ml_1().child(
 9564                        Icon::new(IconName::Info)
 9565                            .size(IconSize::Small)
 9566                            .color(cx.theme().status().error.into()),
 9567                    ),
 9568                )
 9569            })
 9570            .when_some(icon, |element, icon| {
 9571                element.child(
 9572                    div()
 9573                        .mt(px(1.5))
 9574                        .child(Icon::new(icon).size(IconSize::Small)),
 9575                )
 9576            })
 9577    }
 9578
 9579    fn render_edit_prediction_jump_outside_popover(
 9580        &self,
 9581        snapshot: &BufferSnapshot,
 9582        window: &mut Window,
 9583        cx: &mut App,
 9584    ) -> Stateful<Div> {
 9585        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9586        let has_keybind = keybind.is_some();
 9587
 9588        let file_name = snapshot
 9589            .file()
 9590            .map(|file| SharedString::new(file.file_name(cx)))
 9591            .unwrap_or(SharedString::new_static("untitled"));
 9592
 9593        h_flex()
 9594            .id("ep-jump-outside-popover")
 9595            .py_1()
 9596            .px_2()
 9597            .gap_1()
 9598            .rounded_md()
 9599            .border_1()
 9600            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9601            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9602            .shadow_xs()
 9603            .when(!has_keybind, |el| {
 9604                let status_colors = cx.theme().status();
 9605
 9606                el.bg(status_colors.error_background)
 9607                    .border_color(status_colors.error.opacity(0.6))
 9608                    .pl_2()
 9609                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9610                    .cursor_default()
 9611                    .hoverable_tooltip(move |_window, cx| {
 9612                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9613                    })
 9614            })
 9615            .children(keybind)
 9616            .child(
 9617                Label::new(file_name)
 9618                    .size(LabelSize::Small)
 9619                    .buffer_font(cx)
 9620                    .when(!has_keybind, |el| {
 9621                        el.color(cx.theme().status().error.into()).strikethrough()
 9622                    }),
 9623            )
 9624            .when(!has_keybind, |el| {
 9625                el.child(
 9626                    h_flex().ml_1().child(
 9627                        Icon::new(IconName::Info)
 9628                            .size(IconSize::Small)
 9629                            .color(cx.theme().status().error.into()),
 9630                    ),
 9631                )
 9632            })
 9633            .child(
 9634                div()
 9635                    .mt(px(1.5))
 9636                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9637            )
 9638    }
 9639
 9640    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9641        let accent_color = cx.theme().colors().text_accent;
 9642        let editor_bg_color = cx.theme().colors().editor_background;
 9643        editor_bg_color.blend(accent_color.opacity(0.1))
 9644    }
 9645
 9646    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9647        let accent_color = cx.theme().colors().text_accent;
 9648        let editor_bg_color = cx.theme().colors().editor_background;
 9649        editor_bg_color.blend(accent_color.opacity(0.6))
 9650    }
 9651    fn get_prediction_provider_icon_name(
 9652        provider: &Option<RegisteredEditPredictionDelegate>,
 9653    ) -> IconName {
 9654        match provider {
 9655            Some(provider) => match provider.provider.name() {
 9656                "copilot" => IconName::Copilot,
 9657                "supermaven" => IconName::Supermaven,
 9658                _ => IconName::ZedPredict,
 9659            },
 9660            None => IconName::ZedPredict,
 9661        }
 9662    }
 9663
 9664    fn render_edit_prediction_cursor_popover(
 9665        &self,
 9666        min_width: Pixels,
 9667        max_width: Pixels,
 9668        cursor_point: Point,
 9669        style: &EditorStyle,
 9670        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9671        _window: &Window,
 9672        cx: &mut Context<Editor>,
 9673    ) -> Option<AnyElement> {
 9674        let provider = self.edit_prediction_provider.as_ref()?;
 9675        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9676
 9677        let is_refreshing = provider.provider.is_refreshing(cx);
 9678
 9679        fn pending_completion_container(icon: IconName) -> Div {
 9680            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9681        }
 9682
 9683        let completion = match &self.active_edit_prediction {
 9684            Some(prediction) => {
 9685                if !self.has_visible_completions_menu() {
 9686                    const RADIUS: Pixels = px(6.);
 9687                    const BORDER_WIDTH: Pixels = px(1.);
 9688
 9689                    return Some(
 9690                        h_flex()
 9691                            .elevation_2(cx)
 9692                            .border(BORDER_WIDTH)
 9693                            .border_color(cx.theme().colors().border)
 9694                            .when(accept_keystroke.is_none(), |el| {
 9695                                el.border_color(cx.theme().status().error)
 9696                            })
 9697                            .rounded(RADIUS)
 9698                            .rounded_tl(px(0.))
 9699                            .overflow_hidden()
 9700                            .child(div().px_1p5().child(match &prediction.completion {
 9701                                EditPrediction::MoveWithin { target, snapshot } => {
 9702                                    use text::ToPoint as _;
 9703                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9704                                    {
 9705                                        Icon::new(IconName::ZedPredictDown)
 9706                                    } else {
 9707                                        Icon::new(IconName::ZedPredictUp)
 9708                                    }
 9709                                }
 9710                                EditPrediction::MoveOutside { .. } => {
 9711                                    // TODO [zeta2] custom icon for external jump?
 9712                                    Icon::new(provider_icon)
 9713                                }
 9714                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9715                            }))
 9716                            .child(
 9717                                h_flex()
 9718                                    .gap_1()
 9719                                    .py_1()
 9720                                    .px_2()
 9721                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9722                                    .border_l_1()
 9723                                    .border_color(cx.theme().colors().border)
 9724                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9725                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9726                                        el.child(
 9727                                            Label::new("Hold")
 9728                                                .size(LabelSize::Small)
 9729                                                .when(accept_keystroke.is_none(), |el| {
 9730                                                    el.strikethrough()
 9731                                                })
 9732                                                .line_height_style(LineHeightStyle::UiLabel),
 9733                                        )
 9734                                    })
 9735                                    .id("edit_prediction_cursor_popover_keybind")
 9736                                    .when(accept_keystroke.is_none(), |el| {
 9737                                        let status_colors = cx.theme().status();
 9738
 9739                                        el.bg(status_colors.error_background)
 9740                                            .border_color(status_colors.error.opacity(0.6))
 9741                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9742                                            .cursor_default()
 9743                                            .hoverable_tooltip(move |_window, cx| {
 9744                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9745                                                    .into()
 9746                                            })
 9747                                    })
 9748                                    .when_some(
 9749                                        accept_keystroke.as_ref(),
 9750                                        |el, accept_keystroke| {
 9751                                            el.child(h_flex().children(ui::render_modifiers(
 9752                                                accept_keystroke.modifiers(),
 9753                                                PlatformStyle::platform(),
 9754                                                Some(Color::Default),
 9755                                                Some(IconSize::XSmall.rems().into()),
 9756                                                false,
 9757                                            )))
 9758                                        },
 9759                                    ),
 9760                            )
 9761                            .into_any(),
 9762                    );
 9763                }
 9764
 9765                self.render_edit_prediction_cursor_popover_preview(
 9766                    prediction,
 9767                    cursor_point,
 9768                    style,
 9769                    cx,
 9770                )?
 9771            }
 9772
 9773            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9774                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9775                    stale_completion,
 9776                    cursor_point,
 9777                    style,
 9778                    cx,
 9779                )?,
 9780
 9781                None => pending_completion_container(provider_icon)
 9782                    .child(Label::new("...").size(LabelSize::Small)),
 9783            },
 9784
 9785            None => pending_completion_container(provider_icon)
 9786                .child(Label::new("...").size(LabelSize::Small)),
 9787        };
 9788
 9789        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9790            completion
 9791                .with_animation(
 9792                    "loading-completion",
 9793                    Animation::new(Duration::from_secs(2))
 9794                        .repeat()
 9795                        .with_easing(pulsating_between(0.4, 0.8)),
 9796                    |label, delta| label.opacity(delta),
 9797                )
 9798                .into_any_element()
 9799        } else {
 9800            completion.into_any_element()
 9801        };
 9802
 9803        let has_completion = self.active_edit_prediction.is_some();
 9804
 9805        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9806        Some(
 9807            h_flex()
 9808                .min_w(min_width)
 9809                .max_w(max_width)
 9810                .flex_1()
 9811                .elevation_2(cx)
 9812                .border_color(cx.theme().colors().border)
 9813                .child(
 9814                    div()
 9815                        .flex_1()
 9816                        .py_1()
 9817                        .px_2()
 9818                        .overflow_hidden()
 9819                        .child(completion),
 9820                )
 9821                .when_some(accept_keystroke, |el, accept_keystroke| {
 9822                    if !accept_keystroke.modifiers().modified() {
 9823                        return el;
 9824                    }
 9825
 9826                    el.child(
 9827                        h_flex()
 9828                            .h_full()
 9829                            .border_l_1()
 9830                            .rounded_r_lg()
 9831                            .border_color(cx.theme().colors().border)
 9832                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9833                            .gap_1()
 9834                            .py_1()
 9835                            .px_2()
 9836                            .child(
 9837                                h_flex()
 9838                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9839                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9840                                    .child(h_flex().children(ui::render_modifiers(
 9841                                        accept_keystroke.modifiers(),
 9842                                        PlatformStyle::platform(),
 9843                                        Some(if !has_completion {
 9844                                            Color::Muted
 9845                                        } else {
 9846                                            Color::Default
 9847                                        }),
 9848                                        None,
 9849                                        false,
 9850                                    ))),
 9851                            )
 9852                            .child(Label::new("Preview").into_any_element())
 9853                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9854                    )
 9855                })
 9856                .into_any(),
 9857        )
 9858    }
 9859
 9860    fn render_edit_prediction_cursor_popover_preview(
 9861        &self,
 9862        completion: &EditPredictionState,
 9863        cursor_point: Point,
 9864        style: &EditorStyle,
 9865        cx: &mut Context<Editor>,
 9866    ) -> Option<Div> {
 9867        use text::ToPoint as _;
 9868
 9869        fn render_relative_row_jump(
 9870            prefix: impl Into<String>,
 9871            current_row: u32,
 9872            target_row: u32,
 9873        ) -> Div {
 9874            let (row_diff, arrow) = if target_row < current_row {
 9875                (current_row - target_row, IconName::ArrowUp)
 9876            } else {
 9877                (target_row - current_row, IconName::ArrowDown)
 9878            };
 9879
 9880            h_flex()
 9881                .child(
 9882                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9883                        .color(Color::Muted)
 9884                        .size(LabelSize::Small),
 9885                )
 9886                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9887        }
 9888
 9889        let supports_jump = self
 9890            .edit_prediction_provider
 9891            .as_ref()
 9892            .map(|provider| provider.provider.supports_jump_to_edit())
 9893            .unwrap_or(true);
 9894
 9895        match &completion.completion {
 9896            EditPrediction::MoveWithin {
 9897                target, snapshot, ..
 9898            } => {
 9899                if !supports_jump {
 9900                    return None;
 9901                }
 9902
 9903                Some(
 9904                    h_flex()
 9905                        .px_2()
 9906                        .gap_2()
 9907                        .flex_1()
 9908                        .child(
 9909                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9910                                Icon::new(IconName::ZedPredictDown)
 9911                            } else {
 9912                                Icon::new(IconName::ZedPredictUp)
 9913                            },
 9914                        )
 9915                        .child(Label::new("Jump to Edit")),
 9916                )
 9917            }
 9918            EditPrediction::MoveOutside { snapshot, .. } => {
 9919                let file_name = snapshot
 9920                    .file()
 9921                    .map(|file| file.file_name(cx))
 9922                    .unwrap_or("untitled");
 9923                Some(
 9924                    h_flex()
 9925                        .px_2()
 9926                        .gap_2()
 9927                        .flex_1()
 9928                        .child(Icon::new(IconName::ZedPredict))
 9929                        .child(Label::new(format!("Jump to {file_name}"))),
 9930                )
 9931            }
 9932            EditPrediction::Edit {
 9933                edits,
 9934                edit_preview,
 9935                snapshot,
 9936                display_mode: _,
 9937            } => {
 9938                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9939
 9940                let (highlighted_edits, has_more_lines) =
 9941                    if let Some(edit_preview) = edit_preview.as_ref() {
 9942                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9943                            .first_line_preview()
 9944                    } else {
 9945                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9946                    };
 9947
 9948                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9949                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9950
 9951                let preview = h_flex()
 9952                    .gap_1()
 9953                    .min_w_16()
 9954                    .child(styled_text)
 9955                    .when(has_more_lines, |parent| parent.child(""));
 9956
 9957                let left = if supports_jump && first_edit_row != cursor_point.row {
 9958                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9959                        .into_any_element()
 9960                } else {
 9961                    let icon_name =
 9962                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9963                    Icon::new(icon_name).into_any_element()
 9964                };
 9965
 9966                Some(
 9967                    h_flex()
 9968                        .h_full()
 9969                        .flex_1()
 9970                        .gap_2()
 9971                        .pr_1()
 9972                        .overflow_x_hidden()
 9973                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9974                        .child(left)
 9975                        .child(preview),
 9976                )
 9977            }
 9978        }
 9979    }
 9980
 9981    pub fn render_context_menu(
 9982        &mut self,
 9983        max_height_in_lines: u32,
 9984        window: &mut Window,
 9985        cx: &mut Context<Editor>,
 9986    ) -> Option<AnyElement> {
 9987        let menu = self.context_menu.borrow();
 9988        let menu = menu.as_ref()?;
 9989        if !menu.visible() {
 9990            return None;
 9991        };
 9992        self.style
 9993            .as_ref()
 9994            .map(|style| menu.render(style, max_height_in_lines, window, cx))
 9995    }
 9996
 9997    fn render_context_menu_aside(
 9998        &mut self,
 9999        max_size: Size<Pixels>,
10000        window: &mut Window,
10001        cx: &mut Context<Editor>,
10002    ) -> Option<AnyElement> {
10003        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10004            if menu.visible() {
10005                menu.render_aside(max_size, window, cx)
10006            } else {
10007                None
10008            }
10009        })
10010    }
10011
10012    fn hide_context_menu(
10013        &mut self,
10014        window: &mut Window,
10015        cx: &mut Context<Self>,
10016    ) -> Option<CodeContextMenu> {
10017        cx.notify();
10018        self.completion_tasks.clear();
10019        let context_menu = self.context_menu.borrow_mut().take();
10020        self.stale_edit_prediction_in_menu.take();
10021        self.update_visible_edit_prediction(window, cx);
10022        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10023            && let Some(completion_provider) = &self.completion_provider
10024        {
10025            completion_provider.selection_changed(None, window, cx);
10026        }
10027        context_menu
10028    }
10029
10030    fn show_snippet_choices(
10031        &mut self,
10032        choices: &Vec<String>,
10033        selection: Range<Anchor>,
10034        cx: &mut Context<Self>,
10035    ) {
10036        let Some((_, buffer, _)) = self
10037            .buffer()
10038            .read(cx)
10039            .excerpt_containing(selection.start, cx)
10040        else {
10041            return;
10042        };
10043        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10044        else {
10045            return;
10046        };
10047        if buffer != end_buffer {
10048            log::error!("expected anchor range to have matching buffer IDs");
10049            return;
10050        }
10051
10052        let id = post_inc(&mut self.next_completion_id);
10053        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10054        let mut context_menu = self.context_menu.borrow_mut();
10055        let old_menu = context_menu.take();
10056        *context_menu = Some(CodeContextMenu::Completions(
10057            CompletionsMenu::new_snippet_choices(
10058                id,
10059                true,
10060                choices,
10061                selection,
10062                buffer,
10063                old_menu.map(|menu| menu.primary_scroll_handle()),
10064                snippet_sort_order,
10065            ),
10066        ));
10067    }
10068
10069    pub fn insert_snippet(
10070        &mut self,
10071        insertion_ranges: &[Range<MultiBufferOffset>],
10072        snippet: Snippet,
10073        window: &mut Window,
10074        cx: &mut Context<Self>,
10075    ) -> Result<()> {
10076        struct Tabstop<T> {
10077            is_end_tabstop: bool,
10078            ranges: Vec<Range<T>>,
10079            choices: Option<Vec<String>>,
10080        }
10081
10082        let tabstops = self.buffer.update(cx, |buffer, cx| {
10083            let snippet_text: Arc<str> = snippet.text.clone().into();
10084            let edits = insertion_ranges
10085                .iter()
10086                .cloned()
10087                .map(|range| (range, snippet_text.clone()));
10088            let autoindent_mode = AutoindentMode::Block {
10089                original_indent_columns: Vec::new(),
10090            };
10091            buffer.edit(edits, Some(autoindent_mode), cx);
10092
10093            let snapshot = &*buffer.read(cx);
10094            let snippet = &snippet;
10095            snippet
10096                .tabstops
10097                .iter()
10098                .map(|tabstop| {
10099                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10100                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10101                    });
10102                    let mut tabstop_ranges = tabstop
10103                        .ranges
10104                        .iter()
10105                        .flat_map(|tabstop_range| {
10106                            let mut delta = 0_isize;
10107                            insertion_ranges.iter().map(move |insertion_range| {
10108                                let insertion_start = insertion_range.start + delta;
10109                                delta += snippet.text.len() as isize
10110                                    - (insertion_range.end - insertion_range.start) as isize;
10111
10112                                let start =
10113                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10114                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10115                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10116                            })
10117                        })
10118                        .collect::<Vec<_>>();
10119                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10120
10121                    Tabstop {
10122                        is_end_tabstop,
10123                        ranges: tabstop_ranges,
10124                        choices: tabstop.choices.clone(),
10125                    }
10126                })
10127                .collect::<Vec<_>>()
10128        });
10129        if let Some(tabstop) = tabstops.first() {
10130            self.change_selections(Default::default(), window, cx, |s| {
10131                // Reverse order so that the first range is the newest created selection.
10132                // Completions will use it and autoscroll will prioritize it.
10133                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10134            });
10135
10136            if let Some(choices) = &tabstop.choices
10137                && let Some(selection) = tabstop.ranges.first()
10138            {
10139                self.show_snippet_choices(choices, selection.clone(), cx)
10140            }
10141
10142            // If we're already at the last tabstop and it's at the end of the snippet,
10143            // we're done, we don't need to keep the state around.
10144            if !tabstop.is_end_tabstop {
10145                let choices = tabstops
10146                    .iter()
10147                    .map(|tabstop| tabstop.choices.clone())
10148                    .collect();
10149
10150                let ranges = tabstops
10151                    .into_iter()
10152                    .map(|tabstop| tabstop.ranges)
10153                    .collect::<Vec<_>>();
10154
10155                self.snippet_stack.push(SnippetState {
10156                    active_index: 0,
10157                    ranges,
10158                    choices,
10159                });
10160            }
10161
10162            // Check whether the just-entered snippet ends with an auto-closable bracket.
10163            if self.autoclose_regions.is_empty() {
10164                let snapshot = self.buffer.read(cx).snapshot(cx);
10165                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10166                    let selection_head = selection.head();
10167                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10168                        continue;
10169                    };
10170
10171                    let mut bracket_pair = None;
10172                    let max_lookup_length = scope
10173                        .brackets()
10174                        .map(|(pair, _)| {
10175                            pair.start
10176                                .as_str()
10177                                .chars()
10178                                .count()
10179                                .max(pair.end.as_str().chars().count())
10180                        })
10181                        .max();
10182                    if let Some(max_lookup_length) = max_lookup_length {
10183                        let next_text = snapshot
10184                            .chars_at(selection_head)
10185                            .take(max_lookup_length)
10186                            .collect::<String>();
10187                        let prev_text = snapshot
10188                            .reversed_chars_at(selection_head)
10189                            .take(max_lookup_length)
10190                            .collect::<String>();
10191
10192                        for (pair, enabled) in scope.brackets() {
10193                            if enabled
10194                                && pair.close
10195                                && prev_text.starts_with(pair.start.as_str())
10196                                && next_text.starts_with(pair.end.as_str())
10197                            {
10198                                bracket_pair = Some(pair.clone());
10199                                break;
10200                            }
10201                        }
10202                    }
10203
10204                    if let Some(pair) = bracket_pair {
10205                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10206                        let autoclose_enabled =
10207                            self.use_autoclose && snapshot_settings.use_autoclose;
10208                        if autoclose_enabled {
10209                            let start = snapshot.anchor_after(selection_head);
10210                            let end = snapshot.anchor_after(selection_head);
10211                            self.autoclose_regions.push(AutocloseRegion {
10212                                selection_id: selection.id,
10213                                range: start..end,
10214                                pair,
10215                            });
10216                        }
10217                    }
10218                }
10219            }
10220        }
10221        Ok(())
10222    }
10223
10224    pub fn move_to_next_snippet_tabstop(
10225        &mut self,
10226        window: &mut Window,
10227        cx: &mut Context<Self>,
10228    ) -> bool {
10229        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10230    }
10231
10232    pub fn move_to_prev_snippet_tabstop(
10233        &mut self,
10234        window: &mut Window,
10235        cx: &mut Context<Self>,
10236    ) -> bool {
10237        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10238    }
10239
10240    pub fn move_to_snippet_tabstop(
10241        &mut self,
10242        bias: Bias,
10243        window: &mut Window,
10244        cx: &mut Context<Self>,
10245    ) -> bool {
10246        if let Some(mut snippet) = self.snippet_stack.pop() {
10247            match bias {
10248                Bias::Left => {
10249                    if snippet.active_index > 0 {
10250                        snippet.active_index -= 1;
10251                    } else {
10252                        self.snippet_stack.push(snippet);
10253                        return false;
10254                    }
10255                }
10256                Bias::Right => {
10257                    if snippet.active_index + 1 < snippet.ranges.len() {
10258                        snippet.active_index += 1;
10259                    } else {
10260                        self.snippet_stack.push(snippet);
10261                        return false;
10262                    }
10263                }
10264            }
10265            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10266                self.change_selections(Default::default(), window, cx, |s| {
10267                    // Reverse order so that the first range is the newest created selection.
10268                    // Completions will use it and autoscroll will prioritize it.
10269                    s.select_ranges(current_ranges.iter().rev().cloned())
10270                });
10271
10272                if let Some(choices) = &snippet.choices[snippet.active_index]
10273                    && let Some(selection) = current_ranges.first()
10274                {
10275                    self.show_snippet_choices(choices, selection.clone(), cx);
10276                }
10277
10278                // If snippet state is not at the last tabstop, push it back on the stack
10279                if snippet.active_index + 1 < snippet.ranges.len() {
10280                    self.snippet_stack.push(snippet);
10281                }
10282                return true;
10283            }
10284        }
10285
10286        false
10287    }
10288
10289    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10290        self.transact(window, cx, |this, window, cx| {
10291            this.select_all(&SelectAll, window, cx);
10292            this.insert("", window, cx);
10293        });
10294    }
10295
10296    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10297        if self.read_only(cx) {
10298            return;
10299        }
10300        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10301        self.transact(window, cx, |this, window, cx| {
10302            this.select_autoclose_pair(window, cx);
10303
10304            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10305
10306            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10307            if !this.linked_edit_ranges.is_empty() {
10308                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10309                let snapshot = this.buffer.read(cx).snapshot(cx);
10310
10311                for selection in selections.iter() {
10312                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10313                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10314                    if selection_start.buffer_id != selection_end.buffer_id {
10315                        continue;
10316                    }
10317                    if let Some(ranges) =
10318                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10319                    {
10320                        for (buffer, entries) in ranges {
10321                            linked_ranges.entry(buffer).or_default().extend(entries);
10322                        }
10323                    }
10324                }
10325            }
10326
10327            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10328            for selection in &mut selections {
10329                if selection.is_empty() {
10330                    let old_head = selection.head();
10331                    let mut new_head =
10332                        movement::left(&display_map, old_head.to_display_point(&display_map))
10333                            .to_point(&display_map);
10334                    if let Some((buffer, line_buffer_range)) = display_map
10335                        .buffer_snapshot()
10336                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10337                    {
10338                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10339                        let indent_len = match indent_size.kind {
10340                            IndentKind::Space => {
10341                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10342                            }
10343                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10344                        };
10345                        if old_head.column <= indent_size.len && old_head.column > 0 {
10346                            let indent_len = indent_len.get();
10347                            new_head = cmp::min(
10348                                new_head,
10349                                MultiBufferPoint::new(
10350                                    old_head.row,
10351                                    ((old_head.column - 1) / indent_len) * indent_len,
10352                                ),
10353                            );
10354                        }
10355                    }
10356
10357                    selection.set_head(new_head, SelectionGoal::None);
10358                }
10359            }
10360
10361            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10362            this.insert("", window, cx);
10363            let empty_str: Arc<str> = Arc::from("");
10364            for (buffer, edits) in linked_ranges {
10365                let snapshot = buffer.read(cx).snapshot();
10366                use text::ToPoint as TP;
10367
10368                let edits = edits
10369                    .into_iter()
10370                    .map(|range| {
10371                        let end_point = TP::to_point(&range.end, &snapshot);
10372                        let mut start_point = TP::to_point(&range.start, &snapshot);
10373
10374                        if end_point == start_point {
10375                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10376                                .saturating_sub(1);
10377                            start_point =
10378                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10379                        };
10380
10381                        (start_point..end_point, empty_str.clone())
10382                    })
10383                    .sorted_by_key(|(range, _)| range.start)
10384                    .collect::<Vec<_>>();
10385                buffer.update(cx, |this, cx| {
10386                    this.edit(edits, None, cx);
10387                })
10388            }
10389            this.refresh_edit_prediction(true, false, window, cx);
10390            refresh_linked_ranges(this, window, cx);
10391        });
10392    }
10393
10394    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10395        if self.read_only(cx) {
10396            return;
10397        }
10398        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10399        self.transact(window, cx, |this, window, cx| {
10400            this.change_selections(Default::default(), window, cx, |s| {
10401                s.move_with(|map, selection| {
10402                    if selection.is_empty() {
10403                        let cursor = movement::right(map, selection.head());
10404                        selection.end = cursor;
10405                        selection.reversed = true;
10406                        selection.goal = SelectionGoal::None;
10407                    }
10408                })
10409            });
10410            this.insert("", window, cx);
10411            this.refresh_edit_prediction(true, false, window, cx);
10412        });
10413    }
10414
10415    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10416        if self.mode.is_single_line() {
10417            cx.propagate();
10418            return;
10419        }
10420
10421        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10422        if self.move_to_prev_snippet_tabstop(window, cx) {
10423            return;
10424        }
10425        self.outdent(&Outdent, window, cx);
10426    }
10427
10428    pub fn next_snippet_tabstop(
10429        &mut self,
10430        _: &NextSnippetTabstop,
10431        window: &mut Window,
10432        cx: &mut Context<Self>,
10433    ) {
10434        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10435            cx.propagate();
10436            return;
10437        }
10438
10439        if self.move_to_next_snippet_tabstop(window, cx) {
10440            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10441            return;
10442        }
10443        cx.propagate();
10444    }
10445
10446    pub fn previous_snippet_tabstop(
10447        &mut self,
10448        _: &PreviousSnippetTabstop,
10449        window: &mut Window,
10450        cx: &mut Context<Self>,
10451    ) {
10452        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10453            cx.propagate();
10454            return;
10455        }
10456
10457        if self.move_to_prev_snippet_tabstop(window, cx) {
10458            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10459            return;
10460        }
10461        cx.propagate();
10462    }
10463
10464    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10465        if self.mode.is_single_line() {
10466            cx.propagate();
10467            return;
10468        }
10469
10470        if self.move_to_next_snippet_tabstop(window, cx) {
10471            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10472            return;
10473        }
10474        if self.read_only(cx) {
10475            return;
10476        }
10477        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10478        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10479        let buffer = self.buffer.read(cx);
10480        let snapshot = buffer.snapshot(cx);
10481        let rows_iter = selections.iter().map(|s| s.head().row);
10482        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10483
10484        let has_some_cursor_in_whitespace = selections
10485            .iter()
10486            .filter(|selection| selection.is_empty())
10487            .any(|selection| {
10488                let cursor = selection.head();
10489                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10490                cursor.column < current_indent.len
10491            });
10492
10493        let mut edits = Vec::new();
10494        let mut prev_edited_row = 0;
10495        let mut row_delta = 0;
10496        for selection in &mut selections {
10497            if selection.start.row != prev_edited_row {
10498                row_delta = 0;
10499            }
10500            prev_edited_row = selection.end.row;
10501
10502            // If the selection is non-empty, then increase the indentation of the selected lines.
10503            if !selection.is_empty() {
10504                row_delta =
10505                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10506                continue;
10507            }
10508
10509            let cursor = selection.head();
10510            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10511            if let Some(suggested_indent) =
10512                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10513            {
10514                // Don't do anything if already at suggested indent
10515                // and there is any other cursor which is not
10516                if has_some_cursor_in_whitespace
10517                    && cursor.column == current_indent.len
10518                    && current_indent.len == suggested_indent.len
10519                {
10520                    continue;
10521                }
10522
10523                // Adjust line and move cursor to suggested indent
10524                // if cursor is not at suggested indent
10525                if cursor.column < suggested_indent.len
10526                    && cursor.column <= current_indent.len
10527                    && current_indent.len <= suggested_indent.len
10528                {
10529                    selection.start = Point::new(cursor.row, suggested_indent.len);
10530                    selection.end = selection.start;
10531                    if row_delta == 0 {
10532                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10533                            cursor.row,
10534                            current_indent,
10535                            suggested_indent,
10536                        ));
10537                        row_delta = suggested_indent.len - current_indent.len;
10538                    }
10539                    continue;
10540                }
10541
10542                // If current indent is more than suggested indent
10543                // only move cursor to current indent and skip indent
10544                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10545                    selection.start = Point::new(cursor.row, current_indent.len);
10546                    selection.end = selection.start;
10547                    continue;
10548                }
10549            }
10550
10551            // Otherwise, insert a hard or soft tab.
10552            let settings = buffer.language_settings_at(cursor, cx);
10553            let tab_size = if settings.hard_tabs {
10554                IndentSize::tab()
10555            } else {
10556                let tab_size = settings.tab_size.get();
10557                let indent_remainder = snapshot
10558                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10559                    .flat_map(str::chars)
10560                    .fold(row_delta % tab_size, |counter: u32, c| {
10561                        if c == '\t' {
10562                            0
10563                        } else {
10564                            (counter + 1) % tab_size
10565                        }
10566                    });
10567
10568                let chars_to_next_tab_stop = tab_size - indent_remainder;
10569                IndentSize::spaces(chars_to_next_tab_stop)
10570            };
10571            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10572            selection.end = selection.start;
10573            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10574            row_delta += tab_size.len;
10575        }
10576
10577        self.transact(window, cx, |this, window, cx| {
10578            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10579            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10580            this.refresh_edit_prediction(true, false, window, cx);
10581        });
10582    }
10583
10584    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10585        if self.read_only(cx) {
10586            return;
10587        }
10588        if self.mode.is_single_line() {
10589            cx.propagate();
10590            return;
10591        }
10592
10593        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10594        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10595        let mut prev_edited_row = 0;
10596        let mut row_delta = 0;
10597        let mut edits = Vec::new();
10598        let buffer = self.buffer.read(cx);
10599        let snapshot = buffer.snapshot(cx);
10600        for selection in &mut selections {
10601            if selection.start.row != prev_edited_row {
10602                row_delta = 0;
10603            }
10604            prev_edited_row = selection.end.row;
10605
10606            row_delta =
10607                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10608        }
10609
10610        self.transact(window, cx, |this, window, cx| {
10611            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10612            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10613        });
10614    }
10615
10616    fn indent_selection(
10617        buffer: &MultiBuffer,
10618        snapshot: &MultiBufferSnapshot,
10619        selection: &mut Selection<Point>,
10620        edits: &mut Vec<(Range<Point>, String)>,
10621        delta_for_start_row: u32,
10622        cx: &App,
10623    ) -> u32 {
10624        let settings = buffer.language_settings_at(selection.start, cx);
10625        let tab_size = settings.tab_size.get();
10626        let indent_kind = if settings.hard_tabs {
10627            IndentKind::Tab
10628        } else {
10629            IndentKind::Space
10630        };
10631        let mut start_row = selection.start.row;
10632        let mut end_row = selection.end.row + 1;
10633
10634        // If a selection ends at the beginning of a line, don't indent
10635        // that last line.
10636        if selection.end.column == 0 && selection.end.row > selection.start.row {
10637            end_row -= 1;
10638        }
10639
10640        // Avoid re-indenting a row that has already been indented by a
10641        // previous selection, but still update this selection's column
10642        // to reflect that indentation.
10643        if delta_for_start_row > 0 {
10644            start_row += 1;
10645            selection.start.column += delta_for_start_row;
10646            if selection.end.row == selection.start.row {
10647                selection.end.column += delta_for_start_row;
10648            }
10649        }
10650
10651        let mut delta_for_end_row = 0;
10652        let has_multiple_rows = start_row + 1 != end_row;
10653        for row in start_row..end_row {
10654            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10655            let indent_delta = match (current_indent.kind, indent_kind) {
10656                (IndentKind::Space, IndentKind::Space) => {
10657                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10658                    IndentSize::spaces(columns_to_next_tab_stop)
10659                }
10660                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10661                (_, IndentKind::Tab) => IndentSize::tab(),
10662            };
10663
10664            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10665                0
10666            } else {
10667                selection.start.column
10668            };
10669            let row_start = Point::new(row, start);
10670            edits.push((
10671                row_start..row_start,
10672                indent_delta.chars().collect::<String>(),
10673            ));
10674
10675            // Update this selection's endpoints to reflect the indentation.
10676            if row == selection.start.row {
10677                selection.start.column += indent_delta.len;
10678            }
10679            if row == selection.end.row {
10680                selection.end.column += indent_delta.len;
10681                delta_for_end_row = indent_delta.len;
10682            }
10683        }
10684
10685        if selection.start.row == selection.end.row {
10686            delta_for_start_row + delta_for_end_row
10687        } else {
10688            delta_for_end_row
10689        }
10690    }
10691
10692    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10693        if self.read_only(cx) {
10694            return;
10695        }
10696        if self.mode.is_single_line() {
10697            cx.propagate();
10698            return;
10699        }
10700
10701        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10702        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10703        let selections = self.selections.all::<Point>(&display_map);
10704        let mut deletion_ranges = Vec::new();
10705        let mut last_outdent = None;
10706        {
10707            let buffer = self.buffer.read(cx);
10708            let snapshot = buffer.snapshot(cx);
10709            for selection in &selections {
10710                let settings = buffer.language_settings_at(selection.start, cx);
10711                let tab_size = settings.tab_size.get();
10712                let mut rows = selection.spanned_rows(false, &display_map);
10713
10714                // Avoid re-outdenting a row that has already been outdented by a
10715                // previous selection.
10716                if let Some(last_row) = last_outdent
10717                    && last_row == rows.start
10718                {
10719                    rows.start = rows.start.next_row();
10720                }
10721                let has_multiple_rows = rows.len() > 1;
10722                for row in rows.iter_rows() {
10723                    let indent_size = snapshot.indent_size_for_line(row);
10724                    if indent_size.len > 0 {
10725                        let deletion_len = match indent_size.kind {
10726                            IndentKind::Space => {
10727                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10728                                if columns_to_prev_tab_stop == 0 {
10729                                    tab_size
10730                                } else {
10731                                    columns_to_prev_tab_stop
10732                                }
10733                            }
10734                            IndentKind::Tab => 1,
10735                        };
10736                        let start = if has_multiple_rows
10737                            || deletion_len > selection.start.column
10738                            || indent_size.len < selection.start.column
10739                        {
10740                            0
10741                        } else {
10742                            selection.start.column - deletion_len
10743                        };
10744                        deletion_ranges.push(
10745                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10746                        );
10747                        last_outdent = Some(row);
10748                    }
10749                }
10750            }
10751        }
10752
10753        self.transact(window, cx, |this, window, cx| {
10754            this.buffer.update(cx, |buffer, cx| {
10755                let empty_str: Arc<str> = Arc::default();
10756                buffer.edit(
10757                    deletion_ranges
10758                        .into_iter()
10759                        .map(|range| (range, empty_str.clone())),
10760                    None,
10761                    cx,
10762                );
10763            });
10764            let selections = this
10765                .selections
10766                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10767            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10768        });
10769    }
10770
10771    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10772        if self.read_only(cx) {
10773            return;
10774        }
10775        if self.mode.is_single_line() {
10776            cx.propagate();
10777            return;
10778        }
10779
10780        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10781        let selections = self
10782            .selections
10783            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10784            .into_iter()
10785            .map(|s| s.range());
10786
10787        self.transact(window, cx, |this, window, cx| {
10788            this.buffer.update(cx, |buffer, cx| {
10789                buffer.autoindent_ranges(selections, cx);
10790            });
10791            let selections = this
10792                .selections
10793                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10794            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10795        });
10796    }
10797
10798    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10799        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10800        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10801        let selections = self.selections.all::<Point>(&display_map);
10802
10803        let mut new_cursors = Vec::new();
10804        let mut edit_ranges = Vec::new();
10805        let mut selections = selections.iter().peekable();
10806        while let Some(selection) = selections.next() {
10807            let mut rows = selection.spanned_rows(false, &display_map);
10808
10809            // Accumulate contiguous regions of rows that we want to delete.
10810            while let Some(next_selection) = selections.peek() {
10811                let next_rows = next_selection.spanned_rows(false, &display_map);
10812                if next_rows.start <= rows.end {
10813                    rows.end = next_rows.end;
10814                    selections.next().unwrap();
10815                } else {
10816                    break;
10817                }
10818            }
10819
10820            let buffer = display_map.buffer_snapshot();
10821            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10822            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10823                // If there's a line after the range, delete the \n from the end of the row range
10824                (
10825                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10826                    rows.end,
10827                )
10828            } else {
10829                // If there isn't a line after the range, delete the \n from the line before the
10830                // start of the row range
10831                edit_start = edit_start.saturating_sub_usize(1);
10832                (buffer.len(), rows.start.previous_row())
10833            };
10834
10835            let text_layout_details = self.text_layout_details(window);
10836            let x = display_map.x_for_display_point(
10837                selection.head().to_display_point(&display_map),
10838                &text_layout_details,
10839            );
10840            let row = Point::new(target_row.0, 0)
10841                .to_display_point(&display_map)
10842                .row();
10843            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10844
10845            new_cursors.push((
10846                selection.id,
10847                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10848                SelectionGoal::None,
10849            ));
10850            edit_ranges.push(edit_start..edit_end);
10851        }
10852
10853        self.transact(window, cx, |this, window, cx| {
10854            let buffer = this.buffer.update(cx, |buffer, cx| {
10855                let empty_str: Arc<str> = Arc::default();
10856                buffer.edit(
10857                    edit_ranges
10858                        .into_iter()
10859                        .map(|range| (range, empty_str.clone())),
10860                    None,
10861                    cx,
10862                );
10863                buffer.snapshot(cx)
10864            });
10865            let new_selections = new_cursors
10866                .into_iter()
10867                .map(|(id, cursor, goal)| {
10868                    let cursor = cursor.to_point(&buffer);
10869                    Selection {
10870                        id,
10871                        start: cursor,
10872                        end: cursor,
10873                        reversed: false,
10874                        goal,
10875                    }
10876                })
10877                .collect();
10878
10879            this.change_selections(Default::default(), window, cx, |s| {
10880                s.select(new_selections);
10881            });
10882        });
10883    }
10884
10885    pub fn join_lines_impl(
10886        &mut self,
10887        insert_whitespace: bool,
10888        window: &mut Window,
10889        cx: &mut Context<Self>,
10890    ) {
10891        if self.read_only(cx) {
10892            return;
10893        }
10894        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10895        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10896            let start = MultiBufferRow(selection.start.row);
10897            // Treat single line selections as if they include the next line. Otherwise this action
10898            // would do nothing for single line selections individual cursors.
10899            let end = if selection.start.row == selection.end.row {
10900                MultiBufferRow(selection.start.row + 1)
10901            } else {
10902                MultiBufferRow(selection.end.row)
10903            };
10904
10905            if let Some(last_row_range) = row_ranges.last_mut()
10906                && start <= last_row_range.end
10907            {
10908                last_row_range.end = end;
10909                continue;
10910            }
10911            row_ranges.push(start..end);
10912        }
10913
10914        let snapshot = self.buffer.read(cx).snapshot(cx);
10915        let mut cursor_positions = Vec::new();
10916        for row_range in &row_ranges {
10917            let anchor = snapshot.anchor_before(Point::new(
10918                row_range.end.previous_row().0,
10919                snapshot.line_len(row_range.end.previous_row()),
10920            ));
10921            cursor_positions.push(anchor..anchor);
10922        }
10923
10924        self.transact(window, cx, |this, window, cx| {
10925            for row_range in row_ranges.into_iter().rev() {
10926                for row in row_range.iter_rows().rev() {
10927                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10928                    let next_line_row = row.next_row();
10929                    let indent = snapshot.indent_size_for_line(next_line_row);
10930                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10931
10932                    let replace =
10933                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10934                            " "
10935                        } else {
10936                            ""
10937                        };
10938
10939                    this.buffer.update(cx, |buffer, cx| {
10940                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10941                    });
10942                }
10943            }
10944
10945            this.change_selections(Default::default(), window, cx, |s| {
10946                s.select_anchor_ranges(cursor_positions)
10947            });
10948        });
10949    }
10950
10951    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10952        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10953        self.join_lines_impl(true, window, cx);
10954    }
10955
10956    pub fn sort_lines_case_sensitive(
10957        &mut self,
10958        _: &SortLinesCaseSensitive,
10959        window: &mut Window,
10960        cx: &mut Context<Self>,
10961    ) {
10962        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10963    }
10964
10965    pub fn sort_lines_by_length(
10966        &mut self,
10967        _: &SortLinesByLength,
10968        window: &mut Window,
10969        cx: &mut Context<Self>,
10970    ) {
10971        self.manipulate_immutable_lines(window, cx, |lines| {
10972            lines.sort_by_key(|&line| line.chars().count())
10973        })
10974    }
10975
10976    pub fn sort_lines_case_insensitive(
10977        &mut self,
10978        _: &SortLinesCaseInsensitive,
10979        window: &mut Window,
10980        cx: &mut Context<Self>,
10981    ) {
10982        self.manipulate_immutable_lines(window, cx, |lines| {
10983            lines.sort_by_key(|line| line.to_lowercase())
10984        })
10985    }
10986
10987    pub fn unique_lines_case_insensitive(
10988        &mut self,
10989        _: &UniqueLinesCaseInsensitive,
10990        window: &mut Window,
10991        cx: &mut Context<Self>,
10992    ) {
10993        self.manipulate_immutable_lines(window, cx, |lines| {
10994            let mut seen = HashSet::default();
10995            lines.retain(|line| seen.insert(line.to_lowercase()));
10996        })
10997    }
10998
10999    pub fn unique_lines_case_sensitive(
11000        &mut self,
11001        _: &UniqueLinesCaseSensitive,
11002        window: &mut Window,
11003        cx: &mut Context<Self>,
11004    ) {
11005        self.manipulate_immutable_lines(window, cx, |lines| {
11006            let mut seen = HashSet::default();
11007            lines.retain(|line| seen.insert(*line));
11008        })
11009    }
11010
11011    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11012        let snapshot = self.buffer.read(cx).snapshot(cx);
11013        for selection in self.selections.disjoint_anchors_arc().iter() {
11014            if snapshot
11015                .language_at(selection.start)
11016                .and_then(|lang| lang.config().wrap_characters.as_ref())
11017                .is_some()
11018            {
11019                return true;
11020            }
11021        }
11022        false
11023    }
11024
11025    fn wrap_selections_in_tag(
11026        &mut self,
11027        _: &WrapSelectionsInTag,
11028        window: &mut Window,
11029        cx: &mut Context<Self>,
11030    ) {
11031        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11032
11033        let snapshot = self.buffer.read(cx).snapshot(cx);
11034
11035        let mut edits = Vec::new();
11036        let mut boundaries = Vec::new();
11037
11038        for selection in self
11039            .selections
11040            .all_adjusted(&self.display_snapshot(cx))
11041            .iter()
11042        {
11043            let Some(wrap_config) = snapshot
11044                .language_at(selection.start)
11045                .and_then(|lang| lang.config().wrap_characters.clone())
11046            else {
11047                continue;
11048            };
11049
11050            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11051            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11052
11053            let start_before = snapshot.anchor_before(selection.start);
11054            let end_after = snapshot.anchor_after(selection.end);
11055
11056            edits.push((start_before..start_before, open_tag));
11057            edits.push((end_after..end_after, close_tag));
11058
11059            boundaries.push((
11060                start_before,
11061                end_after,
11062                wrap_config.start_prefix.len(),
11063                wrap_config.end_suffix.len(),
11064            ));
11065        }
11066
11067        if edits.is_empty() {
11068            return;
11069        }
11070
11071        self.transact(window, cx, |this, window, cx| {
11072            let buffer = this.buffer.update(cx, |buffer, cx| {
11073                buffer.edit(edits, None, cx);
11074                buffer.snapshot(cx)
11075            });
11076
11077            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11078            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11079                boundaries.into_iter()
11080            {
11081                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11082                let close_offset = end_after
11083                    .to_offset(&buffer)
11084                    .saturating_sub_usize(end_suffix_len);
11085                new_selections.push(open_offset..open_offset);
11086                new_selections.push(close_offset..close_offset);
11087            }
11088
11089            this.change_selections(Default::default(), window, cx, |s| {
11090                s.select_ranges(new_selections);
11091            });
11092
11093            this.request_autoscroll(Autoscroll::fit(), cx);
11094        });
11095    }
11096
11097    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11098        let Some(project) = self.project.clone() else {
11099            return;
11100        };
11101        self.reload(project, window, cx)
11102            .detach_and_notify_err(window, cx);
11103    }
11104
11105    pub fn restore_file(
11106        &mut self,
11107        _: &::git::RestoreFile,
11108        window: &mut Window,
11109        cx: &mut Context<Self>,
11110    ) {
11111        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11112        let mut buffer_ids = HashSet::default();
11113        let snapshot = self.buffer().read(cx).snapshot(cx);
11114        for selection in self
11115            .selections
11116            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11117        {
11118            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11119        }
11120
11121        let buffer = self.buffer().read(cx);
11122        let ranges = buffer_ids
11123            .into_iter()
11124            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11125            .collect::<Vec<_>>();
11126
11127        self.restore_hunks_in_ranges(ranges, window, cx);
11128    }
11129
11130    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11131        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11132        let selections = self
11133            .selections
11134            .all(&self.display_snapshot(cx))
11135            .into_iter()
11136            .map(|s| s.range())
11137            .collect();
11138        self.restore_hunks_in_ranges(selections, window, cx);
11139    }
11140
11141    pub fn restore_hunks_in_ranges(
11142        &mut self,
11143        ranges: Vec<Range<Point>>,
11144        window: &mut Window,
11145        cx: &mut Context<Editor>,
11146    ) {
11147        let mut revert_changes = HashMap::default();
11148        let chunk_by = self
11149            .snapshot(window, cx)
11150            .hunks_for_ranges(ranges)
11151            .into_iter()
11152            .chunk_by(|hunk| hunk.buffer_id);
11153        for (buffer_id, hunks) in &chunk_by {
11154            let hunks = hunks.collect::<Vec<_>>();
11155            for hunk in &hunks {
11156                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11157            }
11158            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11159        }
11160        drop(chunk_by);
11161        if !revert_changes.is_empty() {
11162            self.transact(window, cx, |editor, window, cx| {
11163                editor.restore(revert_changes, window, cx);
11164            });
11165        }
11166    }
11167
11168    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11169        if let Some(status) = self
11170            .addons
11171            .iter()
11172            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11173        {
11174            return Some(status);
11175        }
11176        self.project
11177            .as_ref()?
11178            .read(cx)
11179            .status_for_buffer_id(buffer_id, cx)
11180    }
11181
11182    pub fn open_active_item_in_terminal(
11183        &mut self,
11184        _: &OpenInTerminal,
11185        window: &mut Window,
11186        cx: &mut Context<Self>,
11187    ) {
11188        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11189            let project_path = buffer.read(cx).project_path(cx)?;
11190            let project = self.project()?.read(cx);
11191            let entry = project.entry_for_path(&project_path, cx)?;
11192            let parent = match &entry.canonical_path {
11193                Some(canonical_path) => canonical_path.to_path_buf(),
11194                None => project.absolute_path(&project_path, cx)?,
11195            }
11196            .parent()?
11197            .to_path_buf();
11198            Some(parent)
11199        }) {
11200            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11201        }
11202    }
11203
11204    fn set_breakpoint_context_menu(
11205        &mut self,
11206        display_row: DisplayRow,
11207        position: Option<Anchor>,
11208        clicked_point: gpui::Point<Pixels>,
11209        window: &mut Window,
11210        cx: &mut Context<Self>,
11211    ) {
11212        let source = self
11213            .buffer
11214            .read(cx)
11215            .snapshot(cx)
11216            .anchor_before(Point::new(display_row.0, 0u32));
11217
11218        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11219
11220        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11221            self,
11222            source,
11223            clicked_point,
11224            context_menu,
11225            window,
11226            cx,
11227        );
11228    }
11229
11230    fn add_edit_breakpoint_block(
11231        &mut self,
11232        anchor: Anchor,
11233        breakpoint: &Breakpoint,
11234        edit_action: BreakpointPromptEditAction,
11235        window: &mut Window,
11236        cx: &mut Context<Self>,
11237    ) {
11238        let weak_editor = cx.weak_entity();
11239        let bp_prompt = cx.new(|cx| {
11240            BreakpointPromptEditor::new(
11241                weak_editor,
11242                anchor,
11243                breakpoint.clone(),
11244                edit_action,
11245                window,
11246                cx,
11247            )
11248        });
11249
11250        let height = bp_prompt.update(cx, |this, cx| {
11251            this.prompt
11252                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11253        });
11254        let cloned_prompt = bp_prompt.clone();
11255        let blocks = vec![BlockProperties {
11256            style: BlockStyle::Sticky,
11257            placement: BlockPlacement::Above(anchor),
11258            height: Some(height),
11259            render: Arc::new(move |cx| {
11260                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11261                cloned_prompt.clone().into_any_element()
11262            }),
11263            priority: 0,
11264        }];
11265
11266        let focus_handle = bp_prompt.focus_handle(cx);
11267        window.focus(&focus_handle);
11268
11269        let block_ids = self.insert_blocks(blocks, None, cx);
11270        bp_prompt.update(cx, |prompt, _| {
11271            prompt.add_block_ids(block_ids);
11272        });
11273    }
11274
11275    pub(crate) fn breakpoint_at_row(
11276        &self,
11277        row: u32,
11278        window: &mut Window,
11279        cx: &mut Context<Self>,
11280    ) -> Option<(Anchor, Breakpoint)> {
11281        let snapshot = self.snapshot(window, cx);
11282        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11283
11284        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11285    }
11286
11287    pub(crate) fn breakpoint_at_anchor(
11288        &self,
11289        breakpoint_position: Anchor,
11290        snapshot: &EditorSnapshot,
11291        cx: &mut Context<Self>,
11292    ) -> Option<(Anchor, Breakpoint)> {
11293        let buffer = self
11294            .buffer
11295            .read(cx)
11296            .buffer_for_anchor(breakpoint_position, cx)?;
11297
11298        let enclosing_excerpt = breakpoint_position.excerpt_id;
11299        let buffer_snapshot = buffer.read(cx).snapshot();
11300
11301        let row = buffer_snapshot
11302            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11303            .row;
11304
11305        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11306        let anchor_end = snapshot
11307            .buffer_snapshot()
11308            .anchor_after(Point::new(row, line_len));
11309
11310        self.breakpoint_store
11311            .as_ref()?
11312            .read_with(cx, |breakpoint_store, cx| {
11313                breakpoint_store
11314                    .breakpoints(
11315                        &buffer,
11316                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11317                        &buffer_snapshot,
11318                        cx,
11319                    )
11320                    .next()
11321                    .and_then(|(bp, _)| {
11322                        let breakpoint_row = buffer_snapshot
11323                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11324                            .row;
11325
11326                        if breakpoint_row == row {
11327                            snapshot
11328                                .buffer_snapshot()
11329                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11330                                .map(|position| (position, bp.bp.clone()))
11331                        } else {
11332                            None
11333                        }
11334                    })
11335            })
11336    }
11337
11338    pub fn edit_log_breakpoint(
11339        &mut self,
11340        _: &EditLogBreakpoint,
11341        window: &mut Window,
11342        cx: &mut Context<Self>,
11343    ) {
11344        if self.breakpoint_store.is_none() {
11345            return;
11346        }
11347
11348        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11349            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11350                message: None,
11351                state: BreakpointState::Enabled,
11352                condition: None,
11353                hit_condition: None,
11354            });
11355
11356            self.add_edit_breakpoint_block(
11357                anchor,
11358                &breakpoint,
11359                BreakpointPromptEditAction::Log,
11360                window,
11361                cx,
11362            );
11363        }
11364    }
11365
11366    fn breakpoints_at_cursors(
11367        &self,
11368        window: &mut Window,
11369        cx: &mut Context<Self>,
11370    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11371        let snapshot = self.snapshot(window, cx);
11372        let cursors = self
11373            .selections
11374            .disjoint_anchors_arc()
11375            .iter()
11376            .map(|selection| {
11377                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11378
11379                let breakpoint_position = self
11380                    .breakpoint_at_row(cursor_position.row, window, cx)
11381                    .map(|bp| bp.0)
11382                    .unwrap_or_else(|| {
11383                        snapshot
11384                            .display_snapshot
11385                            .buffer_snapshot()
11386                            .anchor_after(Point::new(cursor_position.row, 0))
11387                    });
11388
11389                let breakpoint = self
11390                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11391                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11392
11393                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11394            })
11395            // 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.
11396            .collect::<HashMap<Anchor, _>>();
11397
11398        cursors.into_iter().collect()
11399    }
11400
11401    pub fn enable_breakpoint(
11402        &mut self,
11403        _: &crate::actions::EnableBreakpoint,
11404        window: &mut Window,
11405        cx: &mut Context<Self>,
11406    ) {
11407        if self.breakpoint_store.is_none() {
11408            return;
11409        }
11410
11411        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11412            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11413                continue;
11414            };
11415            self.edit_breakpoint_at_anchor(
11416                anchor,
11417                breakpoint,
11418                BreakpointEditAction::InvertState,
11419                cx,
11420            );
11421        }
11422    }
11423
11424    pub fn disable_breakpoint(
11425        &mut self,
11426        _: &crate::actions::DisableBreakpoint,
11427        window: &mut Window,
11428        cx: &mut Context<Self>,
11429    ) {
11430        if self.breakpoint_store.is_none() {
11431            return;
11432        }
11433
11434        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11435            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11436                continue;
11437            };
11438            self.edit_breakpoint_at_anchor(
11439                anchor,
11440                breakpoint,
11441                BreakpointEditAction::InvertState,
11442                cx,
11443            );
11444        }
11445    }
11446
11447    pub fn toggle_breakpoint(
11448        &mut self,
11449        _: &crate::actions::ToggleBreakpoint,
11450        window: &mut Window,
11451        cx: &mut Context<Self>,
11452    ) {
11453        if self.breakpoint_store.is_none() {
11454            return;
11455        }
11456
11457        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11458            if let Some(breakpoint) = breakpoint {
11459                self.edit_breakpoint_at_anchor(
11460                    anchor,
11461                    breakpoint,
11462                    BreakpointEditAction::Toggle,
11463                    cx,
11464                );
11465            } else {
11466                self.edit_breakpoint_at_anchor(
11467                    anchor,
11468                    Breakpoint::new_standard(),
11469                    BreakpointEditAction::Toggle,
11470                    cx,
11471                );
11472            }
11473        }
11474    }
11475
11476    pub fn edit_breakpoint_at_anchor(
11477        &mut self,
11478        breakpoint_position: Anchor,
11479        breakpoint: Breakpoint,
11480        edit_action: BreakpointEditAction,
11481        cx: &mut Context<Self>,
11482    ) {
11483        let Some(breakpoint_store) = &self.breakpoint_store else {
11484            return;
11485        };
11486
11487        let Some(buffer) = self
11488            .buffer
11489            .read(cx)
11490            .buffer_for_anchor(breakpoint_position, cx)
11491        else {
11492            return;
11493        };
11494
11495        breakpoint_store.update(cx, |breakpoint_store, cx| {
11496            breakpoint_store.toggle_breakpoint(
11497                buffer,
11498                BreakpointWithPosition {
11499                    position: breakpoint_position.text_anchor,
11500                    bp: breakpoint,
11501                },
11502                edit_action,
11503                cx,
11504            );
11505        });
11506
11507        cx.notify();
11508    }
11509
11510    #[cfg(any(test, feature = "test-support"))]
11511    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11512        self.breakpoint_store.clone()
11513    }
11514
11515    pub fn prepare_restore_change(
11516        &self,
11517        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11518        hunk: &MultiBufferDiffHunk,
11519        cx: &mut App,
11520    ) -> Option<()> {
11521        if hunk.is_created_file() {
11522            return None;
11523        }
11524        let buffer = self.buffer.read(cx);
11525        let diff = buffer.diff_for(hunk.buffer_id)?;
11526        let buffer = buffer.buffer(hunk.buffer_id)?;
11527        let buffer = buffer.read(cx);
11528        let original_text = diff
11529            .read(cx)
11530            .base_text()
11531            .as_rope()
11532            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11533        let buffer_snapshot = buffer.snapshot();
11534        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11535        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11536            probe
11537                .0
11538                .start
11539                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11540                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11541        }) {
11542            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11543            Some(())
11544        } else {
11545            None
11546        }
11547    }
11548
11549    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11550        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11551    }
11552
11553    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11554        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11555    }
11556
11557    pub fn rotate_selections_forward(
11558        &mut self,
11559        _: &RotateSelectionsForward,
11560        window: &mut Window,
11561        cx: &mut Context<Self>,
11562    ) {
11563        self.rotate_selections(window, cx, false)
11564    }
11565
11566    pub fn rotate_selections_backward(
11567        &mut self,
11568        _: &RotateSelectionsBackward,
11569        window: &mut Window,
11570        cx: &mut Context<Self>,
11571    ) {
11572        self.rotate_selections(window, cx, true)
11573    }
11574
11575    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11576        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11577        let display_snapshot = self.display_snapshot(cx);
11578        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11579
11580        if selections.len() < 2 {
11581            return;
11582        }
11583
11584        let (edits, new_selections) = {
11585            let buffer = self.buffer.read(cx).read(cx);
11586            let has_selections = selections.iter().any(|s| !s.is_empty());
11587            if has_selections {
11588                let mut selected_texts: Vec<String> = selections
11589                    .iter()
11590                    .map(|selection| {
11591                        buffer
11592                            .text_for_range(selection.start..selection.end)
11593                            .collect()
11594                    })
11595                    .collect();
11596
11597                if reverse {
11598                    selected_texts.rotate_left(1);
11599                } else {
11600                    selected_texts.rotate_right(1);
11601                }
11602
11603                let mut offset_delta: i64 = 0;
11604                let mut new_selections = Vec::new();
11605                let edits: Vec<_> = selections
11606                    .iter()
11607                    .zip(selected_texts.iter())
11608                    .map(|(selection, new_text)| {
11609                        let old_len = (selection.end.0 - selection.start.0) as i64;
11610                        let new_len = new_text.len() as i64;
11611                        let adjusted_start =
11612                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11613                        let adjusted_end =
11614                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11615
11616                        new_selections.push(Selection {
11617                            id: selection.id,
11618                            start: adjusted_start,
11619                            end: adjusted_end,
11620                            reversed: selection.reversed,
11621                            goal: selection.goal,
11622                        });
11623
11624                        offset_delta += new_len - old_len;
11625                        (selection.start..selection.end, new_text.clone())
11626                    })
11627                    .collect();
11628                (edits, new_selections)
11629            } else {
11630                let mut all_rows: Vec<u32> = selections
11631                    .iter()
11632                    .map(|selection| buffer.offset_to_point(selection.start).row)
11633                    .collect();
11634                all_rows.sort_unstable();
11635                all_rows.dedup();
11636
11637                if all_rows.len() < 2 {
11638                    return;
11639                }
11640
11641                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11642                    .iter()
11643                    .map(|&row| {
11644                        let start = Point::new(row, 0);
11645                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11646                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11647                    })
11648                    .collect();
11649
11650                let mut line_texts: Vec<String> = line_ranges
11651                    .iter()
11652                    .map(|range| buffer.text_for_range(range.clone()).collect())
11653                    .collect();
11654
11655                if reverse {
11656                    line_texts.rotate_left(1);
11657                } else {
11658                    line_texts.rotate_right(1);
11659                }
11660
11661                let edits = line_ranges
11662                    .iter()
11663                    .zip(line_texts.iter())
11664                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11665                    .collect();
11666
11667                let num_rows = all_rows.len();
11668                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11669                    .iter()
11670                    .enumerate()
11671                    .map(|(i, &row)| (row, i))
11672                    .collect();
11673
11674                // Compute new line start offsets after rotation (handles CRLF)
11675                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11676                let first_line_start = line_ranges[0].start.0;
11677                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11678                for text in line_texts.iter().take(num_rows - 1) {
11679                    let prev_start = *new_line_starts.last().unwrap();
11680                    new_line_starts.push(prev_start + text.len() + newline_len);
11681                }
11682
11683                let new_selections = selections
11684                    .iter()
11685                    .map(|selection| {
11686                        let point = buffer.offset_to_point(selection.start);
11687                        let old_index = row_to_index[&point.row];
11688                        let new_index = if reverse {
11689                            (old_index + num_rows - 1) % num_rows
11690                        } else {
11691                            (old_index + 1) % num_rows
11692                        };
11693                        let new_offset =
11694                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11695                        Selection {
11696                            id: selection.id,
11697                            start: new_offset,
11698                            end: new_offset,
11699                            reversed: selection.reversed,
11700                            goal: selection.goal,
11701                        }
11702                    })
11703                    .collect();
11704
11705                (edits, new_selections)
11706            }
11707        };
11708
11709        self.transact(window, cx, |this, window, cx| {
11710            this.buffer.update(cx, |buffer, cx| {
11711                buffer.edit(edits, None, cx);
11712            });
11713            this.change_selections(Default::default(), window, cx, |s| {
11714                s.select(new_selections);
11715            });
11716        });
11717    }
11718
11719    fn manipulate_lines<M>(
11720        &mut self,
11721        window: &mut Window,
11722        cx: &mut Context<Self>,
11723        mut manipulate: M,
11724    ) where
11725        M: FnMut(&str) -> LineManipulationResult,
11726    {
11727        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11728
11729        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11730        let buffer = self.buffer.read(cx).snapshot(cx);
11731
11732        let mut edits = Vec::new();
11733
11734        let selections = self.selections.all::<Point>(&display_map);
11735        let mut selections = selections.iter().peekable();
11736        let mut contiguous_row_selections = Vec::new();
11737        let mut new_selections = Vec::new();
11738        let mut added_lines = 0;
11739        let mut removed_lines = 0;
11740
11741        while let Some(selection) = selections.next() {
11742            let (start_row, end_row) = consume_contiguous_rows(
11743                &mut contiguous_row_selections,
11744                selection,
11745                &display_map,
11746                &mut selections,
11747            );
11748
11749            let start_point = Point::new(start_row.0, 0);
11750            let end_point = Point::new(
11751                end_row.previous_row().0,
11752                buffer.line_len(end_row.previous_row()),
11753            );
11754            let text = buffer
11755                .text_for_range(start_point..end_point)
11756                .collect::<String>();
11757
11758            let LineManipulationResult {
11759                new_text,
11760                line_count_before,
11761                line_count_after,
11762            } = manipulate(&text);
11763
11764            edits.push((start_point..end_point, new_text));
11765
11766            // Selections must change based on added and removed line count
11767            let start_row =
11768                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11769            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11770            new_selections.push(Selection {
11771                id: selection.id,
11772                start: start_row,
11773                end: end_row,
11774                goal: SelectionGoal::None,
11775                reversed: selection.reversed,
11776            });
11777
11778            if line_count_after > line_count_before {
11779                added_lines += line_count_after - line_count_before;
11780            } else if line_count_before > line_count_after {
11781                removed_lines += line_count_before - line_count_after;
11782            }
11783        }
11784
11785        self.transact(window, cx, |this, window, cx| {
11786            let buffer = this.buffer.update(cx, |buffer, cx| {
11787                buffer.edit(edits, None, cx);
11788                buffer.snapshot(cx)
11789            });
11790
11791            // Recalculate offsets on newly edited buffer
11792            let new_selections = new_selections
11793                .iter()
11794                .map(|s| {
11795                    let start_point = Point::new(s.start.0, 0);
11796                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11797                    Selection {
11798                        id: s.id,
11799                        start: buffer.point_to_offset(start_point),
11800                        end: buffer.point_to_offset(end_point),
11801                        goal: s.goal,
11802                        reversed: s.reversed,
11803                    }
11804                })
11805                .collect();
11806
11807            this.change_selections(Default::default(), window, cx, |s| {
11808                s.select(new_selections);
11809            });
11810
11811            this.request_autoscroll(Autoscroll::fit(), cx);
11812        });
11813    }
11814
11815    fn manipulate_immutable_lines<Fn>(
11816        &mut self,
11817        window: &mut Window,
11818        cx: &mut Context<Self>,
11819        mut callback: Fn,
11820    ) where
11821        Fn: FnMut(&mut Vec<&str>),
11822    {
11823        self.manipulate_lines(window, cx, |text| {
11824            let mut lines: Vec<&str> = text.split('\n').collect();
11825            let line_count_before = lines.len();
11826
11827            callback(&mut lines);
11828
11829            LineManipulationResult {
11830                new_text: lines.join("\n"),
11831                line_count_before,
11832                line_count_after: lines.len(),
11833            }
11834        });
11835    }
11836
11837    fn manipulate_mutable_lines<Fn>(
11838        &mut self,
11839        window: &mut Window,
11840        cx: &mut Context<Self>,
11841        mut callback: Fn,
11842    ) where
11843        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11844    {
11845        self.manipulate_lines(window, cx, |text| {
11846            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11847            let line_count_before = lines.len();
11848
11849            callback(&mut lines);
11850
11851            LineManipulationResult {
11852                new_text: lines.join("\n"),
11853                line_count_before,
11854                line_count_after: lines.len(),
11855            }
11856        });
11857    }
11858
11859    pub fn convert_indentation_to_spaces(
11860        &mut self,
11861        _: &ConvertIndentationToSpaces,
11862        window: &mut Window,
11863        cx: &mut Context<Self>,
11864    ) {
11865        let settings = self.buffer.read(cx).language_settings(cx);
11866        let tab_size = settings.tab_size.get() as usize;
11867
11868        self.manipulate_mutable_lines(window, cx, |lines| {
11869            // Allocates a reasonably sized scratch buffer once for the whole loop
11870            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11871            // Avoids recomputing spaces that could be inserted many times
11872            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11873                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11874                .collect();
11875
11876            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11877                let mut chars = line.as_ref().chars();
11878                let mut col = 0;
11879                let mut changed = false;
11880
11881                for ch in chars.by_ref() {
11882                    match ch {
11883                        ' ' => {
11884                            reindented_line.push(' ');
11885                            col += 1;
11886                        }
11887                        '\t' => {
11888                            // \t are converted to spaces depending on the current column
11889                            let spaces_len = tab_size - (col % tab_size);
11890                            reindented_line.extend(&space_cache[spaces_len - 1]);
11891                            col += spaces_len;
11892                            changed = true;
11893                        }
11894                        _ => {
11895                            // If we dont append before break, the character is consumed
11896                            reindented_line.push(ch);
11897                            break;
11898                        }
11899                    }
11900                }
11901
11902                if !changed {
11903                    reindented_line.clear();
11904                    continue;
11905                }
11906                // Append the rest of the line and replace old reference with new one
11907                reindented_line.extend(chars);
11908                *line = Cow::Owned(reindented_line.clone());
11909                reindented_line.clear();
11910            }
11911        });
11912    }
11913
11914    pub fn convert_indentation_to_tabs(
11915        &mut self,
11916        _: &ConvertIndentationToTabs,
11917        window: &mut Window,
11918        cx: &mut Context<Self>,
11919    ) {
11920        let settings = self.buffer.read(cx).language_settings(cx);
11921        let tab_size = settings.tab_size.get() as usize;
11922
11923        self.manipulate_mutable_lines(window, cx, |lines| {
11924            // Allocates a reasonably sized buffer once for the whole loop
11925            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11926            // Avoids recomputing spaces that could be inserted many times
11927            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11928                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11929                .collect();
11930
11931            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11932                let mut chars = line.chars();
11933                let mut spaces_count = 0;
11934                let mut first_non_indent_char = None;
11935                let mut changed = false;
11936
11937                for ch in chars.by_ref() {
11938                    match ch {
11939                        ' ' => {
11940                            // Keep track of spaces. Append \t when we reach tab_size
11941                            spaces_count += 1;
11942                            changed = true;
11943                            if spaces_count == tab_size {
11944                                reindented_line.push('\t');
11945                                spaces_count = 0;
11946                            }
11947                        }
11948                        '\t' => {
11949                            reindented_line.push('\t');
11950                            spaces_count = 0;
11951                        }
11952                        _ => {
11953                            // Dont append it yet, we might have remaining spaces
11954                            first_non_indent_char = Some(ch);
11955                            break;
11956                        }
11957                    }
11958                }
11959
11960                if !changed {
11961                    reindented_line.clear();
11962                    continue;
11963                }
11964                // Remaining spaces that didn't make a full tab stop
11965                if spaces_count > 0 {
11966                    reindented_line.extend(&space_cache[spaces_count - 1]);
11967                }
11968                // If we consume an extra character that was not indentation, add it back
11969                if let Some(extra_char) = first_non_indent_char {
11970                    reindented_line.push(extra_char);
11971                }
11972                // Append the rest of the line and replace old reference with new one
11973                reindented_line.extend(chars);
11974                *line = Cow::Owned(reindented_line.clone());
11975                reindented_line.clear();
11976            }
11977        });
11978    }
11979
11980    pub fn convert_to_upper_case(
11981        &mut self,
11982        _: &ConvertToUpperCase,
11983        window: &mut Window,
11984        cx: &mut Context<Self>,
11985    ) {
11986        self.manipulate_text(window, cx, |text| text.to_uppercase())
11987    }
11988
11989    pub fn convert_to_lower_case(
11990        &mut self,
11991        _: &ConvertToLowerCase,
11992        window: &mut Window,
11993        cx: &mut Context<Self>,
11994    ) {
11995        self.manipulate_text(window, cx, |text| text.to_lowercase())
11996    }
11997
11998    pub fn convert_to_title_case(
11999        &mut self,
12000        _: &ConvertToTitleCase,
12001        window: &mut Window,
12002        cx: &mut Context<Self>,
12003    ) {
12004        self.manipulate_text(window, cx, |text| {
12005            text.split('\n')
12006                .map(|line| line.to_case(Case::Title))
12007                .join("\n")
12008        })
12009    }
12010
12011    pub fn convert_to_snake_case(
12012        &mut self,
12013        _: &ConvertToSnakeCase,
12014        window: &mut Window,
12015        cx: &mut Context<Self>,
12016    ) {
12017        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
12018    }
12019
12020    pub fn convert_to_kebab_case(
12021        &mut self,
12022        _: &ConvertToKebabCase,
12023        window: &mut Window,
12024        cx: &mut Context<Self>,
12025    ) {
12026        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
12027    }
12028
12029    pub fn convert_to_upper_camel_case(
12030        &mut self,
12031        _: &ConvertToUpperCamelCase,
12032        window: &mut Window,
12033        cx: &mut Context<Self>,
12034    ) {
12035        self.manipulate_text(window, cx, |text| {
12036            text.split('\n')
12037                .map(|line| line.to_case(Case::UpperCamel))
12038                .join("\n")
12039        })
12040    }
12041
12042    pub fn convert_to_lower_camel_case(
12043        &mut self,
12044        _: &ConvertToLowerCamelCase,
12045        window: &mut Window,
12046        cx: &mut Context<Self>,
12047    ) {
12048        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
12049    }
12050
12051    pub fn convert_to_opposite_case(
12052        &mut self,
12053        _: &ConvertToOppositeCase,
12054        window: &mut Window,
12055        cx: &mut Context<Self>,
12056    ) {
12057        self.manipulate_text(window, cx, |text| {
12058            text.chars()
12059                .fold(String::with_capacity(text.len()), |mut t, c| {
12060                    if c.is_uppercase() {
12061                        t.extend(c.to_lowercase());
12062                    } else {
12063                        t.extend(c.to_uppercase());
12064                    }
12065                    t
12066                })
12067        })
12068    }
12069
12070    pub fn convert_to_sentence_case(
12071        &mut self,
12072        _: &ConvertToSentenceCase,
12073        window: &mut Window,
12074        cx: &mut Context<Self>,
12075    ) {
12076        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12077    }
12078
12079    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12080        self.manipulate_text(window, cx, |text| {
12081            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12082            if has_upper_case_characters {
12083                text.to_lowercase()
12084            } else {
12085                text.to_uppercase()
12086            }
12087        })
12088    }
12089
12090    pub fn convert_to_rot13(
12091        &mut self,
12092        _: &ConvertToRot13,
12093        window: &mut Window,
12094        cx: &mut Context<Self>,
12095    ) {
12096        self.manipulate_text(window, cx, |text| {
12097            text.chars()
12098                .map(|c| match c {
12099                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12100                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12101                    _ => c,
12102                })
12103                .collect()
12104        })
12105    }
12106
12107    pub fn convert_to_rot47(
12108        &mut self,
12109        _: &ConvertToRot47,
12110        window: &mut Window,
12111        cx: &mut Context<Self>,
12112    ) {
12113        self.manipulate_text(window, cx, |text| {
12114            text.chars()
12115                .map(|c| {
12116                    let code_point = c as u32;
12117                    if code_point >= 33 && code_point <= 126 {
12118                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12119                    }
12120                    c
12121                })
12122                .collect()
12123        })
12124    }
12125
12126    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12127    where
12128        Fn: FnMut(&str) -> String,
12129    {
12130        let buffer = self.buffer.read(cx).snapshot(cx);
12131
12132        let mut new_selections = Vec::new();
12133        let mut edits = Vec::new();
12134        let mut selection_adjustment = 0isize;
12135
12136        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12137            let selection_is_empty = selection.is_empty();
12138
12139            let (start, end) = if selection_is_empty {
12140                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12141                (word_range.start, word_range.end)
12142            } else {
12143                (
12144                    buffer.point_to_offset(selection.start),
12145                    buffer.point_to_offset(selection.end),
12146                )
12147            };
12148
12149            let text = buffer.text_for_range(start..end).collect::<String>();
12150            let old_length = text.len() as isize;
12151            let text = callback(&text);
12152
12153            new_selections.push(Selection {
12154                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12155                end: MultiBufferOffset(
12156                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12157                ),
12158                goal: SelectionGoal::None,
12159                id: selection.id,
12160                reversed: selection.reversed,
12161            });
12162
12163            selection_adjustment += old_length - text.len() as isize;
12164
12165            edits.push((start..end, text));
12166        }
12167
12168        self.transact(window, cx, |this, window, cx| {
12169            this.buffer.update(cx, |buffer, cx| {
12170                buffer.edit(edits, None, cx);
12171            });
12172
12173            this.change_selections(Default::default(), window, cx, |s| {
12174                s.select(new_selections);
12175            });
12176
12177            this.request_autoscroll(Autoscroll::fit(), cx);
12178        });
12179    }
12180
12181    pub fn move_selection_on_drop(
12182        &mut self,
12183        selection: &Selection<Anchor>,
12184        target: DisplayPoint,
12185        is_cut: bool,
12186        window: &mut Window,
12187        cx: &mut Context<Self>,
12188    ) {
12189        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12190        let buffer = display_map.buffer_snapshot();
12191        let mut edits = Vec::new();
12192        let insert_point = display_map
12193            .clip_point(target, Bias::Left)
12194            .to_point(&display_map);
12195        let text = buffer
12196            .text_for_range(selection.start..selection.end)
12197            .collect::<String>();
12198        if is_cut {
12199            edits.push(((selection.start..selection.end), String::new()));
12200        }
12201        let insert_anchor = buffer.anchor_before(insert_point);
12202        edits.push(((insert_anchor..insert_anchor), text));
12203        let last_edit_start = insert_anchor.bias_left(buffer);
12204        let last_edit_end = insert_anchor.bias_right(buffer);
12205        self.transact(window, cx, |this, window, cx| {
12206            this.buffer.update(cx, |buffer, cx| {
12207                buffer.edit(edits, None, cx);
12208            });
12209            this.change_selections(Default::default(), window, cx, |s| {
12210                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12211            });
12212        });
12213    }
12214
12215    pub fn clear_selection_drag_state(&mut self) {
12216        self.selection_drag_state = SelectionDragState::None;
12217    }
12218
12219    pub fn duplicate(
12220        &mut self,
12221        upwards: bool,
12222        whole_lines: bool,
12223        window: &mut Window,
12224        cx: &mut Context<Self>,
12225    ) {
12226        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12227
12228        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12229        let buffer = display_map.buffer_snapshot();
12230        let selections = self.selections.all::<Point>(&display_map);
12231
12232        let mut edits = Vec::new();
12233        let mut selections_iter = selections.iter().peekable();
12234        while let Some(selection) = selections_iter.next() {
12235            let mut rows = selection.spanned_rows(false, &display_map);
12236            // duplicate line-wise
12237            if whole_lines || selection.start == selection.end {
12238                // Avoid duplicating the same lines twice.
12239                while let Some(next_selection) = selections_iter.peek() {
12240                    let next_rows = next_selection.spanned_rows(false, &display_map);
12241                    if next_rows.start < rows.end {
12242                        rows.end = next_rows.end;
12243                        selections_iter.next().unwrap();
12244                    } else {
12245                        break;
12246                    }
12247                }
12248
12249                // Copy the text from the selected row region and splice it either at the start
12250                // or end of the region.
12251                let start = Point::new(rows.start.0, 0);
12252                let end = Point::new(
12253                    rows.end.previous_row().0,
12254                    buffer.line_len(rows.end.previous_row()),
12255                );
12256
12257                let mut text = buffer.text_for_range(start..end).collect::<String>();
12258
12259                let insert_location = if upwards {
12260                    // When duplicating upward, we need to insert before the current line.
12261                    // If we're on the last line and it doesn't end with a newline,
12262                    // we need to add a newline before the duplicated content.
12263                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12264                        && buffer.max_point().column > 0
12265                        && !text.ends_with('\n');
12266
12267                    if needs_leading_newline {
12268                        text.insert(0, '\n');
12269                        end
12270                    } else {
12271                        text.push('\n');
12272                        Point::new(rows.start.0, 0)
12273                    }
12274                } else {
12275                    text.push('\n');
12276                    start
12277                };
12278                edits.push((insert_location..insert_location, text));
12279            } else {
12280                // duplicate character-wise
12281                let start = selection.start;
12282                let end = selection.end;
12283                let text = buffer.text_for_range(start..end).collect::<String>();
12284                edits.push((selection.end..selection.end, text));
12285            }
12286        }
12287
12288        self.transact(window, cx, |this, window, cx| {
12289            this.buffer.update(cx, |buffer, cx| {
12290                buffer.edit(edits, None, cx);
12291            });
12292
12293            // When duplicating upward with whole lines, move the cursor to the duplicated line
12294            if upwards && whole_lines {
12295                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12296
12297                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12298                    let mut new_ranges = Vec::new();
12299                    let selections = s.all::<Point>(&display_map);
12300                    let mut selections_iter = selections.iter().peekable();
12301
12302                    while let Some(first_selection) = selections_iter.next() {
12303                        // Group contiguous selections together to find the total row span
12304                        let mut group_selections = vec![first_selection];
12305                        let mut rows = first_selection.spanned_rows(false, &display_map);
12306
12307                        while let Some(next_selection) = selections_iter.peek() {
12308                            let next_rows = next_selection.spanned_rows(false, &display_map);
12309                            if next_rows.start < rows.end {
12310                                rows.end = next_rows.end;
12311                                group_selections.push(selections_iter.next().unwrap());
12312                            } else {
12313                                break;
12314                            }
12315                        }
12316
12317                        let row_count = rows.end.0 - rows.start.0;
12318
12319                        // Move all selections in this group up by the total number of duplicated rows
12320                        for selection in group_selections {
12321                            let new_start = Point::new(
12322                                selection.start.row.saturating_sub(row_count),
12323                                selection.start.column,
12324                            );
12325
12326                            let new_end = Point::new(
12327                                selection.end.row.saturating_sub(row_count),
12328                                selection.end.column,
12329                            );
12330
12331                            new_ranges.push(new_start..new_end);
12332                        }
12333                    }
12334
12335                    s.select_ranges(new_ranges);
12336                });
12337            }
12338
12339            this.request_autoscroll(Autoscroll::fit(), cx);
12340        });
12341    }
12342
12343    pub fn duplicate_line_up(
12344        &mut self,
12345        _: &DuplicateLineUp,
12346        window: &mut Window,
12347        cx: &mut Context<Self>,
12348    ) {
12349        self.duplicate(true, true, window, cx);
12350    }
12351
12352    pub fn duplicate_line_down(
12353        &mut self,
12354        _: &DuplicateLineDown,
12355        window: &mut Window,
12356        cx: &mut Context<Self>,
12357    ) {
12358        self.duplicate(false, true, window, cx);
12359    }
12360
12361    pub fn duplicate_selection(
12362        &mut self,
12363        _: &DuplicateSelection,
12364        window: &mut Window,
12365        cx: &mut Context<Self>,
12366    ) {
12367        self.duplicate(false, false, window, cx);
12368    }
12369
12370    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12371        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12372        if self.mode.is_single_line() {
12373            cx.propagate();
12374            return;
12375        }
12376
12377        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12378        let buffer = self.buffer.read(cx).snapshot(cx);
12379
12380        let mut edits = Vec::new();
12381        let mut unfold_ranges = Vec::new();
12382        let mut refold_creases = Vec::new();
12383
12384        let selections = self.selections.all::<Point>(&display_map);
12385        let mut selections = selections.iter().peekable();
12386        let mut contiguous_row_selections = Vec::new();
12387        let mut new_selections = Vec::new();
12388
12389        while let Some(selection) = selections.next() {
12390            // Find all the selections that span a contiguous row range
12391            let (start_row, end_row) = consume_contiguous_rows(
12392                &mut contiguous_row_selections,
12393                selection,
12394                &display_map,
12395                &mut selections,
12396            );
12397
12398            // Move the text spanned by the row range to be before the line preceding the row range
12399            if start_row.0 > 0 {
12400                let range_to_move = Point::new(
12401                    start_row.previous_row().0,
12402                    buffer.line_len(start_row.previous_row()),
12403                )
12404                    ..Point::new(
12405                        end_row.previous_row().0,
12406                        buffer.line_len(end_row.previous_row()),
12407                    );
12408                let insertion_point = display_map
12409                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12410                    .0;
12411
12412                // Don't move lines across excerpts
12413                if buffer
12414                    .excerpt_containing(insertion_point..range_to_move.end)
12415                    .is_some()
12416                {
12417                    let text = buffer
12418                        .text_for_range(range_to_move.clone())
12419                        .flat_map(|s| s.chars())
12420                        .skip(1)
12421                        .chain(['\n'])
12422                        .collect::<String>();
12423
12424                    edits.push((
12425                        buffer.anchor_after(range_to_move.start)
12426                            ..buffer.anchor_before(range_to_move.end),
12427                        String::new(),
12428                    ));
12429                    let insertion_anchor = buffer.anchor_after(insertion_point);
12430                    edits.push((insertion_anchor..insertion_anchor, text));
12431
12432                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12433
12434                    // Move selections up
12435                    new_selections.extend(contiguous_row_selections.drain(..).map(
12436                        |mut selection| {
12437                            selection.start.row -= row_delta;
12438                            selection.end.row -= row_delta;
12439                            selection
12440                        },
12441                    ));
12442
12443                    // Move folds up
12444                    unfold_ranges.push(range_to_move.clone());
12445                    for fold in display_map.folds_in_range(
12446                        buffer.anchor_before(range_to_move.start)
12447                            ..buffer.anchor_after(range_to_move.end),
12448                    ) {
12449                        let mut start = fold.range.start.to_point(&buffer);
12450                        let mut end = fold.range.end.to_point(&buffer);
12451                        start.row -= row_delta;
12452                        end.row -= row_delta;
12453                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12454                    }
12455                }
12456            }
12457
12458            // If we didn't move line(s), preserve the existing selections
12459            new_selections.append(&mut contiguous_row_selections);
12460        }
12461
12462        self.transact(window, cx, |this, window, cx| {
12463            this.unfold_ranges(&unfold_ranges, true, true, cx);
12464            this.buffer.update(cx, |buffer, cx| {
12465                for (range, text) in edits {
12466                    buffer.edit([(range, text)], None, cx);
12467                }
12468            });
12469            this.fold_creases(refold_creases, true, window, cx);
12470            this.change_selections(Default::default(), window, cx, |s| {
12471                s.select(new_selections);
12472            })
12473        });
12474    }
12475
12476    pub fn move_line_down(
12477        &mut self,
12478        _: &MoveLineDown,
12479        window: &mut Window,
12480        cx: &mut Context<Self>,
12481    ) {
12482        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12483        if self.mode.is_single_line() {
12484            cx.propagate();
12485            return;
12486        }
12487
12488        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12489        let buffer = self.buffer.read(cx).snapshot(cx);
12490
12491        let mut edits = Vec::new();
12492        let mut unfold_ranges = Vec::new();
12493        let mut refold_creases = Vec::new();
12494
12495        let selections = self.selections.all::<Point>(&display_map);
12496        let mut selections = selections.iter().peekable();
12497        let mut contiguous_row_selections = Vec::new();
12498        let mut new_selections = Vec::new();
12499
12500        while let Some(selection) = selections.next() {
12501            // Find all the selections that span a contiguous row range
12502            let (start_row, end_row) = consume_contiguous_rows(
12503                &mut contiguous_row_selections,
12504                selection,
12505                &display_map,
12506                &mut selections,
12507            );
12508
12509            // Move the text spanned by the row range to be after the last line of the row range
12510            if end_row.0 <= buffer.max_point().row {
12511                let range_to_move =
12512                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12513                let insertion_point = display_map
12514                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12515                    .0;
12516
12517                // Don't move lines across excerpt boundaries
12518                if buffer
12519                    .excerpt_containing(range_to_move.start..insertion_point)
12520                    .is_some()
12521                {
12522                    let mut text = String::from("\n");
12523                    text.extend(buffer.text_for_range(range_to_move.clone()));
12524                    text.pop(); // Drop trailing newline
12525                    edits.push((
12526                        buffer.anchor_after(range_to_move.start)
12527                            ..buffer.anchor_before(range_to_move.end),
12528                        String::new(),
12529                    ));
12530                    let insertion_anchor = buffer.anchor_after(insertion_point);
12531                    edits.push((insertion_anchor..insertion_anchor, text));
12532
12533                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12534
12535                    // Move selections down
12536                    new_selections.extend(contiguous_row_selections.drain(..).map(
12537                        |mut selection| {
12538                            selection.start.row += row_delta;
12539                            selection.end.row += row_delta;
12540                            selection
12541                        },
12542                    ));
12543
12544                    // Move folds down
12545                    unfold_ranges.push(range_to_move.clone());
12546                    for fold in display_map.folds_in_range(
12547                        buffer.anchor_before(range_to_move.start)
12548                            ..buffer.anchor_after(range_to_move.end),
12549                    ) {
12550                        let mut start = fold.range.start.to_point(&buffer);
12551                        let mut end = fold.range.end.to_point(&buffer);
12552                        start.row += row_delta;
12553                        end.row += row_delta;
12554                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12555                    }
12556                }
12557            }
12558
12559            // If we didn't move line(s), preserve the existing selections
12560            new_selections.append(&mut contiguous_row_selections);
12561        }
12562
12563        self.transact(window, cx, |this, window, cx| {
12564            this.unfold_ranges(&unfold_ranges, true, true, cx);
12565            this.buffer.update(cx, |buffer, cx| {
12566                for (range, text) in edits {
12567                    buffer.edit([(range, text)], None, cx);
12568                }
12569            });
12570            this.fold_creases(refold_creases, true, window, cx);
12571            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12572        });
12573    }
12574
12575    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12576        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12577        let text_layout_details = &self.text_layout_details(window);
12578        self.transact(window, cx, |this, window, cx| {
12579            let edits = this.change_selections(Default::default(), window, cx, |s| {
12580                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12581                s.move_with(|display_map, selection| {
12582                    if !selection.is_empty() {
12583                        return;
12584                    }
12585
12586                    let mut head = selection.head();
12587                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12588                    if head.column() == display_map.line_len(head.row()) {
12589                        transpose_offset = display_map
12590                            .buffer_snapshot()
12591                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12592                    }
12593
12594                    if transpose_offset == MultiBufferOffset(0) {
12595                        return;
12596                    }
12597
12598                    *head.column_mut() += 1;
12599                    head = display_map.clip_point(head, Bias::Right);
12600                    let goal = SelectionGoal::HorizontalPosition(
12601                        display_map
12602                            .x_for_display_point(head, text_layout_details)
12603                            .into(),
12604                    );
12605                    selection.collapse_to(head, goal);
12606
12607                    let transpose_start = display_map
12608                        .buffer_snapshot()
12609                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12610                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12611                        let transpose_end = display_map
12612                            .buffer_snapshot()
12613                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12614                        if let Some(ch) = display_map
12615                            .buffer_snapshot()
12616                            .chars_at(transpose_start)
12617                            .next()
12618                        {
12619                            edits.push((transpose_start..transpose_offset, String::new()));
12620                            edits.push((transpose_end..transpose_end, ch.to_string()));
12621                        }
12622                    }
12623                });
12624                edits
12625            });
12626            this.buffer
12627                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12628            let selections = this
12629                .selections
12630                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12631            this.change_selections(Default::default(), window, cx, |s| {
12632                s.select(selections);
12633            });
12634        });
12635    }
12636
12637    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12638        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12639        if self.mode.is_single_line() {
12640            cx.propagate();
12641            return;
12642        }
12643
12644        self.rewrap_impl(RewrapOptions::default(), cx)
12645    }
12646
12647    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12648        let buffer = self.buffer.read(cx).snapshot(cx);
12649        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12650
12651        #[derive(Clone, Debug, PartialEq)]
12652        enum CommentFormat {
12653            /// single line comment, with prefix for line
12654            Line(String),
12655            /// single line within a block comment, with prefix for line
12656            BlockLine(String),
12657            /// a single line of a block comment that includes the initial delimiter
12658            BlockCommentWithStart(BlockCommentConfig),
12659            /// a single line of a block comment that includes the ending delimiter
12660            BlockCommentWithEnd(BlockCommentConfig),
12661        }
12662
12663        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12664        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12665            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12666                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12667                .peekable();
12668
12669            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12670                row
12671            } else {
12672                return Vec::new();
12673            };
12674
12675            let language_settings = buffer.language_settings_at(selection.head(), cx);
12676            let language_scope = buffer.language_scope_at(selection.head());
12677
12678            let indent_and_prefix_for_row =
12679                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12680                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12681                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12682                        &language_scope
12683                    {
12684                        let indent_end = Point::new(row, indent.len);
12685                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12686                        let line_text_after_indent = buffer
12687                            .text_for_range(indent_end..line_end)
12688                            .collect::<String>();
12689
12690                        let is_within_comment_override = buffer
12691                            .language_scope_at(indent_end)
12692                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12693                        let comment_delimiters = if is_within_comment_override {
12694                            // we are within a comment syntax node, but we don't
12695                            // yet know what kind of comment: block, doc or line
12696                            match (
12697                                language_scope.documentation_comment(),
12698                                language_scope.block_comment(),
12699                            ) {
12700                                (Some(config), _) | (_, Some(config))
12701                                    if buffer.contains_str_at(indent_end, &config.start) =>
12702                                {
12703                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12704                                }
12705                                (Some(config), _) | (_, Some(config))
12706                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12707                                {
12708                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12709                                }
12710                                (Some(config), _) | (_, Some(config))
12711                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12712                                {
12713                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12714                                }
12715                                (_, _) => language_scope
12716                                    .line_comment_prefixes()
12717                                    .iter()
12718                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12719                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12720                            }
12721                        } else {
12722                            // we not in an overridden comment node, but we may
12723                            // be within a non-overridden line comment node
12724                            language_scope
12725                                .line_comment_prefixes()
12726                                .iter()
12727                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12728                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12729                        };
12730
12731                        let rewrap_prefix = language_scope
12732                            .rewrap_prefixes()
12733                            .iter()
12734                            .find_map(|prefix_regex| {
12735                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12736                                    if mat.start() == 0 {
12737                                        Some(mat.as_str().to_string())
12738                                    } else {
12739                                        None
12740                                    }
12741                                })
12742                            })
12743                            .flatten();
12744                        (comment_delimiters, rewrap_prefix)
12745                    } else {
12746                        (None, None)
12747                    };
12748                    (indent, comment_prefix, rewrap_prefix)
12749                };
12750
12751            let mut ranges = Vec::new();
12752            let from_empty_selection = selection.is_empty();
12753
12754            let mut current_range_start = first_row;
12755            let mut prev_row = first_row;
12756            let (
12757                mut current_range_indent,
12758                mut current_range_comment_delimiters,
12759                mut current_range_rewrap_prefix,
12760            ) = indent_and_prefix_for_row(first_row);
12761
12762            for row in non_blank_rows_iter.skip(1) {
12763                let has_paragraph_break = row > prev_row + 1;
12764
12765                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12766                    indent_and_prefix_for_row(row);
12767
12768                let has_indent_change = row_indent != current_range_indent;
12769                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12770
12771                let has_boundary_change = has_comment_change
12772                    || row_rewrap_prefix.is_some()
12773                    || (has_indent_change && current_range_comment_delimiters.is_some());
12774
12775                if has_paragraph_break || has_boundary_change {
12776                    ranges.push((
12777                        language_settings.clone(),
12778                        Point::new(current_range_start, 0)
12779                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12780                        current_range_indent,
12781                        current_range_comment_delimiters.clone(),
12782                        current_range_rewrap_prefix.clone(),
12783                        from_empty_selection,
12784                    ));
12785                    current_range_start = row;
12786                    current_range_indent = row_indent;
12787                    current_range_comment_delimiters = row_comment_delimiters;
12788                    current_range_rewrap_prefix = row_rewrap_prefix;
12789                }
12790                prev_row = row;
12791            }
12792
12793            ranges.push((
12794                language_settings.clone(),
12795                Point::new(current_range_start, 0)
12796                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12797                current_range_indent,
12798                current_range_comment_delimiters,
12799                current_range_rewrap_prefix,
12800                from_empty_selection,
12801            ));
12802
12803            ranges
12804        });
12805
12806        let mut edits = Vec::new();
12807        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12808
12809        for (
12810            language_settings,
12811            wrap_range,
12812            mut indent_size,
12813            comment_prefix,
12814            rewrap_prefix,
12815            from_empty_selection,
12816        ) in wrap_ranges
12817        {
12818            let mut start_row = wrap_range.start.row;
12819            let mut end_row = wrap_range.end.row;
12820
12821            // Skip selections that overlap with a range that has already been rewrapped.
12822            let selection_range = start_row..end_row;
12823            if rewrapped_row_ranges
12824                .iter()
12825                .any(|range| range.overlaps(&selection_range))
12826            {
12827                continue;
12828            }
12829
12830            let tab_size = language_settings.tab_size;
12831
12832            let (line_prefix, inside_comment) = match &comment_prefix {
12833                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12834                    (Some(prefix.as_str()), true)
12835                }
12836                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12837                    (Some(prefix.as_ref()), true)
12838                }
12839                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12840                    start: _,
12841                    end: _,
12842                    prefix,
12843                    tab_size,
12844                })) => {
12845                    indent_size.len += tab_size;
12846                    (Some(prefix.as_ref()), true)
12847                }
12848                None => (None, false),
12849            };
12850            let indent_prefix = indent_size.chars().collect::<String>();
12851            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12852
12853            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12854                RewrapBehavior::InComments => inside_comment,
12855                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12856                RewrapBehavior::Anywhere => true,
12857            };
12858
12859            let should_rewrap = options.override_language_settings
12860                || allow_rewrap_based_on_language
12861                || self.hard_wrap.is_some();
12862            if !should_rewrap {
12863                continue;
12864            }
12865
12866            if from_empty_selection {
12867                'expand_upwards: while start_row > 0 {
12868                    let prev_row = start_row - 1;
12869                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12870                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12871                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12872                    {
12873                        start_row = prev_row;
12874                    } else {
12875                        break 'expand_upwards;
12876                    }
12877                }
12878
12879                'expand_downwards: while end_row < buffer.max_point().row {
12880                    let next_row = end_row + 1;
12881                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12882                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12883                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12884                    {
12885                        end_row = next_row;
12886                    } else {
12887                        break 'expand_downwards;
12888                    }
12889                }
12890            }
12891
12892            let start = Point::new(start_row, 0);
12893            let start_offset = ToOffset::to_offset(&start, &buffer);
12894            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12895            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12896            let mut first_line_delimiter = None;
12897            let mut last_line_delimiter = None;
12898            let Some(lines_without_prefixes) = selection_text
12899                .lines()
12900                .enumerate()
12901                .map(|(ix, line)| {
12902                    let line_trimmed = line.trim_start();
12903                    if rewrap_prefix.is_some() && ix > 0 {
12904                        Ok(line_trimmed)
12905                    } else if let Some(
12906                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12907                            start,
12908                            prefix,
12909                            end,
12910                            tab_size,
12911                        })
12912                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12913                            start,
12914                            prefix,
12915                            end,
12916                            tab_size,
12917                        }),
12918                    ) = &comment_prefix
12919                    {
12920                        let line_trimmed = line_trimmed
12921                            .strip_prefix(start.as_ref())
12922                            .map(|s| {
12923                                let mut indent_size = indent_size;
12924                                indent_size.len -= tab_size;
12925                                let indent_prefix: String = indent_size.chars().collect();
12926                                first_line_delimiter = Some((indent_prefix, start));
12927                                s.trim_start()
12928                            })
12929                            .unwrap_or(line_trimmed);
12930                        let line_trimmed = line_trimmed
12931                            .strip_suffix(end.as_ref())
12932                            .map(|s| {
12933                                last_line_delimiter = Some(end);
12934                                s.trim_end()
12935                            })
12936                            .unwrap_or(line_trimmed);
12937                        let line_trimmed = line_trimmed
12938                            .strip_prefix(prefix.as_ref())
12939                            .unwrap_or(line_trimmed);
12940                        Ok(line_trimmed)
12941                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12942                        line_trimmed.strip_prefix(prefix).with_context(|| {
12943                            format!("line did not start with prefix {prefix:?}: {line:?}")
12944                        })
12945                    } else {
12946                        line_trimmed
12947                            .strip_prefix(&line_prefix.trim_start())
12948                            .with_context(|| {
12949                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12950                            })
12951                    }
12952                })
12953                .collect::<Result<Vec<_>, _>>()
12954                .log_err()
12955            else {
12956                continue;
12957            };
12958
12959            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12960                buffer
12961                    .language_settings_at(Point::new(start_row, 0), cx)
12962                    .preferred_line_length as usize
12963            });
12964
12965            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12966                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12967            } else {
12968                line_prefix.clone()
12969            };
12970
12971            let wrapped_text = {
12972                let mut wrapped_text = wrap_with_prefix(
12973                    line_prefix,
12974                    subsequent_lines_prefix,
12975                    lines_without_prefixes.join("\n"),
12976                    wrap_column,
12977                    tab_size,
12978                    options.preserve_existing_whitespace,
12979                );
12980
12981                if let Some((indent, delimiter)) = first_line_delimiter {
12982                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12983                }
12984                if let Some(last_line) = last_line_delimiter {
12985                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12986                }
12987
12988                wrapped_text
12989            };
12990
12991            // TODO: should always use char-based diff while still supporting cursor behavior that
12992            // matches vim.
12993            let mut diff_options = DiffOptions::default();
12994            if options.override_language_settings {
12995                diff_options.max_word_diff_len = 0;
12996                diff_options.max_word_diff_line_count = 0;
12997            } else {
12998                diff_options.max_word_diff_len = usize::MAX;
12999                diff_options.max_word_diff_line_count = usize::MAX;
13000            }
13001
13002            for (old_range, new_text) in
13003                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13004            {
13005                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13006                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13007                edits.push((edit_start..edit_end, new_text));
13008            }
13009
13010            rewrapped_row_ranges.push(start_row..=end_row);
13011        }
13012
13013        self.buffer
13014            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13015    }
13016
13017    pub fn cut_common(
13018        &mut self,
13019        cut_no_selection_line: bool,
13020        window: &mut Window,
13021        cx: &mut Context<Self>,
13022    ) -> ClipboardItem {
13023        let mut text = String::new();
13024        let buffer = self.buffer.read(cx).snapshot(cx);
13025        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13026        let mut clipboard_selections = Vec::with_capacity(selections.len());
13027        {
13028            let max_point = buffer.max_point();
13029            let mut is_first = true;
13030            let mut prev_selection_was_entire_line = false;
13031            for selection in &mut selections {
13032                let is_entire_line =
13033                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13034                if is_entire_line {
13035                    selection.start = Point::new(selection.start.row, 0);
13036                    if !selection.is_empty() && selection.end.column == 0 {
13037                        selection.end = cmp::min(max_point, selection.end);
13038                    } else {
13039                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13040                    }
13041                    selection.goal = SelectionGoal::None;
13042                }
13043                if is_first {
13044                    is_first = false;
13045                } else if !prev_selection_was_entire_line {
13046                    text += "\n";
13047                }
13048                prev_selection_was_entire_line = is_entire_line;
13049                let mut len = 0;
13050                for chunk in buffer.text_for_range(selection.start..selection.end) {
13051                    text.push_str(chunk);
13052                    len += chunk.len();
13053                }
13054
13055                clipboard_selections.push(ClipboardSelection::for_buffer(
13056                    len,
13057                    is_entire_line,
13058                    selection.range(),
13059                    &buffer,
13060                    self.project.as_ref(),
13061                    cx,
13062                ));
13063            }
13064        }
13065
13066        self.transact(window, cx, |this, window, cx| {
13067            this.change_selections(Default::default(), window, cx, |s| {
13068                s.select(selections);
13069            });
13070            this.insert("", window, cx);
13071        });
13072        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13073    }
13074
13075    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13076        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13077        let item = self.cut_common(true, window, cx);
13078        cx.write_to_clipboard(item);
13079    }
13080
13081    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13082        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13083        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13084            s.move_with(|snapshot, sel| {
13085                if sel.is_empty() {
13086                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13087                }
13088                if sel.is_empty() {
13089                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13090                }
13091            });
13092        });
13093        let item = self.cut_common(false, window, cx);
13094        cx.set_global(KillRing(item))
13095    }
13096
13097    pub fn kill_ring_yank(
13098        &mut self,
13099        _: &KillRingYank,
13100        window: &mut Window,
13101        cx: &mut Context<Self>,
13102    ) {
13103        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13104        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13105            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13106                (kill_ring.text().to_string(), kill_ring.metadata_json())
13107            } else {
13108                return;
13109            }
13110        } else {
13111            return;
13112        };
13113        self.do_paste(&text, metadata, false, window, cx);
13114    }
13115
13116    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13117        self.do_copy(true, cx);
13118    }
13119
13120    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13121        self.do_copy(false, cx);
13122    }
13123
13124    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13125        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13126        let buffer = self.buffer.read(cx).read(cx);
13127        let mut text = String::new();
13128
13129        let mut clipboard_selections = Vec::with_capacity(selections.len());
13130        {
13131            let max_point = buffer.max_point();
13132            let mut is_first = true;
13133            let mut prev_selection_was_entire_line = false;
13134            for selection in &selections {
13135                let mut start = selection.start;
13136                let mut end = selection.end;
13137                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13138                let mut add_trailing_newline = false;
13139                if is_entire_line {
13140                    start = Point::new(start.row, 0);
13141                    let next_line_start = Point::new(end.row + 1, 0);
13142                    if next_line_start <= max_point {
13143                        end = next_line_start;
13144                    } else {
13145                        // We're on the last line without a trailing newline.
13146                        // Copy to the end of the line and add a newline afterwards.
13147                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13148                        add_trailing_newline = true;
13149                    }
13150                }
13151
13152                let mut trimmed_selections = Vec::new();
13153                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13154                    let row = MultiBufferRow(start.row);
13155                    let first_indent = buffer.indent_size_for_line(row);
13156                    if first_indent.len == 0 || start.column > first_indent.len {
13157                        trimmed_selections.push(start..end);
13158                    } else {
13159                        trimmed_selections.push(
13160                            Point::new(row.0, first_indent.len)
13161                                ..Point::new(row.0, buffer.line_len(row)),
13162                        );
13163                        for row in start.row + 1..=end.row {
13164                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13165                            if row == end.row {
13166                                line_len = end.column;
13167                            }
13168                            if line_len == 0 {
13169                                trimmed_selections
13170                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13171                                continue;
13172                            }
13173                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13174                            if row_indent_size.len >= first_indent.len {
13175                                trimmed_selections.push(
13176                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13177                                );
13178                            } else {
13179                                trimmed_selections.clear();
13180                                trimmed_selections.push(start..end);
13181                                break;
13182                            }
13183                        }
13184                    }
13185                } else {
13186                    trimmed_selections.push(start..end);
13187                }
13188
13189                for trimmed_range in trimmed_selections {
13190                    if is_first {
13191                        is_first = false;
13192                    } else if !prev_selection_was_entire_line {
13193                        text += "\n";
13194                    }
13195                    prev_selection_was_entire_line = is_entire_line;
13196                    let mut len = 0;
13197                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13198                        text.push_str(chunk);
13199                        len += chunk.len();
13200                    }
13201                    if add_trailing_newline {
13202                        text.push('\n');
13203                        len += 1;
13204                    }
13205                    clipboard_selections.push(ClipboardSelection::for_buffer(
13206                        len,
13207                        is_entire_line,
13208                        trimmed_range,
13209                        &buffer,
13210                        self.project.as_ref(),
13211                        cx,
13212                    ));
13213                }
13214            }
13215        }
13216
13217        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13218            text,
13219            clipboard_selections,
13220        ));
13221    }
13222
13223    pub fn do_paste(
13224        &mut self,
13225        text: &String,
13226        clipboard_selections: Option<Vec<ClipboardSelection>>,
13227        handle_entire_lines: bool,
13228        window: &mut Window,
13229        cx: &mut Context<Self>,
13230    ) {
13231        if self.read_only(cx) {
13232            return;
13233        }
13234
13235        let clipboard_text = Cow::Borrowed(text.as_str());
13236
13237        self.transact(window, cx, |this, window, cx| {
13238            let had_active_edit_prediction = this.has_active_edit_prediction();
13239            let display_map = this.display_snapshot(cx);
13240            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13241            let cursor_offset = this
13242                .selections
13243                .last::<MultiBufferOffset>(&display_map)
13244                .head();
13245
13246            if let Some(mut clipboard_selections) = clipboard_selections {
13247                let all_selections_were_entire_line =
13248                    clipboard_selections.iter().all(|s| s.is_entire_line);
13249                let first_selection_indent_column =
13250                    clipboard_selections.first().map(|s| s.first_line_indent);
13251                if clipboard_selections.len() != old_selections.len() {
13252                    clipboard_selections.drain(..);
13253                }
13254                let mut auto_indent_on_paste = true;
13255
13256                this.buffer.update(cx, |buffer, cx| {
13257                    let snapshot = buffer.read(cx);
13258                    auto_indent_on_paste = snapshot
13259                        .language_settings_at(cursor_offset, cx)
13260                        .auto_indent_on_paste;
13261
13262                    let mut start_offset = 0;
13263                    let mut edits = Vec::new();
13264                    let mut original_indent_columns = Vec::new();
13265                    for (ix, selection) in old_selections.iter().enumerate() {
13266                        let to_insert;
13267                        let entire_line;
13268                        let original_indent_column;
13269                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13270                            let end_offset = start_offset + clipboard_selection.len;
13271                            to_insert = &clipboard_text[start_offset..end_offset];
13272                            entire_line = clipboard_selection.is_entire_line;
13273                            start_offset = if entire_line {
13274                                end_offset
13275                            } else {
13276                                end_offset + 1
13277                            };
13278                            original_indent_column = Some(clipboard_selection.first_line_indent);
13279                        } else {
13280                            to_insert = &*clipboard_text;
13281                            entire_line = all_selections_were_entire_line;
13282                            original_indent_column = first_selection_indent_column
13283                        }
13284
13285                        let (range, to_insert) =
13286                            if selection.is_empty() && handle_entire_lines && entire_line {
13287                                // If the corresponding selection was empty when this slice of the
13288                                // clipboard text was written, then the entire line containing the
13289                                // selection was copied. If this selection is also currently empty,
13290                                // then paste the line before the current line of the buffer.
13291                                let column = selection.start.to_point(&snapshot).column as usize;
13292                                let line_start = selection.start - column;
13293                                (line_start..line_start, Cow::Borrowed(to_insert))
13294                            } else {
13295                                let language = snapshot.language_at(selection.head());
13296                                let range = selection.range();
13297                                if let Some(language) = language
13298                                    && language.name() == "Markdown".into()
13299                                {
13300                                    edit_for_markdown_paste(
13301                                        &snapshot,
13302                                        range,
13303                                        to_insert,
13304                                        url::Url::parse(to_insert).ok(),
13305                                    )
13306                                } else {
13307                                    (range, Cow::Borrowed(to_insert))
13308                                }
13309                            };
13310
13311                        edits.push((range, to_insert));
13312                        original_indent_columns.push(original_indent_column);
13313                    }
13314                    drop(snapshot);
13315
13316                    buffer.edit(
13317                        edits,
13318                        if auto_indent_on_paste {
13319                            Some(AutoindentMode::Block {
13320                                original_indent_columns,
13321                            })
13322                        } else {
13323                            None
13324                        },
13325                        cx,
13326                    );
13327                });
13328
13329                let selections = this
13330                    .selections
13331                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13332                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13333            } else {
13334                let url = url::Url::parse(&clipboard_text).ok();
13335
13336                let auto_indent_mode = if !clipboard_text.is_empty() {
13337                    Some(AutoindentMode::Block {
13338                        original_indent_columns: Vec::new(),
13339                    })
13340                } else {
13341                    None
13342                };
13343
13344                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13345                    let snapshot = buffer.snapshot(cx);
13346
13347                    let anchors = old_selections
13348                        .iter()
13349                        .map(|s| {
13350                            let anchor = snapshot.anchor_after(s.head());
13351                            s.map(|_| anchor)
13352                        })
13353                        .collect::<Vec<_>>();
13354
13355                    let mut edits = Vec::new();
13356
13357                    for selection in old_selections.iter() {
13358                        let language = snapshot.language_at(selection.head());
13359                        let range = selection.range();
13360
13361                        let (edit_range, edit_text) = if let Some(language) = language
13362                            && language.name() == "Markdown".into()
13363                        {
13364                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13365                        } else {
13366                            (range, clipboard_text.clone())
13367                        };
13368
13369                        edits.push((edit_range, edit_text));
13370                    }
13371
13372                    drop(snapshot);
13373                    buffer.edit(edits, auto_indent_mode, cx);
13374
13375                    anchors
13376                });
13377
13378                this.change_selections(Default::default(), window, cx, |s| {
13379                    s.select_anchors(selection_anchors);
13380                });
13381            }
13382
13383            //   🤔                 |    ..     | show_in_menu |
13384            // | ..                  |   true        true
13385            // | had_edit_prediction |   false       true
13386
13387            let trigger_in_words =
13388                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13389
13390            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13391        });
13392    }
13393
13394    pub fn diff_clipboard_with_selection(
13395        &mut self,
13396        _: &DiffClipboardWithSelection,
13397        window: &mut Window,
13398        cx: &mut Context<Self>,
13399    ) {
13400        let selections = self
13401            .selections
13402            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13403
13404        if selections.is_empty() {
13405            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13406            return;
13407        };
13408
13409        let clipboard_text = match cx.read_from_clipboard() {
13410            Some(item) => match item.entries().first() {
13411                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13412                _ => None,
13413            },
13414            None => None,
13415        };
13416
13417        let Some(clipboard_text) = clipboard_text else {
13418            log::warn!("Clipboard doesn't contain text.");
13419            return;
13420        };
13421
13422        window.dispatch_action(
13423            Box::new(DiffClipboardWithSelectionData {
13424                clipboard_text,
13425                editor: cx.entity(),
13426            }),
13427            cx,
13428        );
13429    }
13430
13431    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13432        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13433        if let Some(item) = cx.read_from_clipboard() {
13434            let entries = item.entries();
13435
13436            match entries.first() {
13437                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13438                // of all the pasted entries.
13439                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13440                    .do_paste(
13441                        clipboard_string.text(),
13442                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13443                        true,
13444                        window,
13445                        cx,
13446                    ),
13447                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13448            }
13449        }
13450    }
13451
13452    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13453        if self.read_only(cx) {
13454            return;
13455        }
13456
13457        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13458
13459        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13460            if let Some((selections, _)) =
13461                self.selection_history.transaction(transaction_id).cloned()
13462            {
13463                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13464                    s.select_anchors(selections.to_vec());
13465                });
13466            } else {
13467                log::error!(
13468                    "No entry in selection_history found for undo. \
13469                     This may correspond to a bug where undo does not update the selection. \
13470                     If this is occurring, please add details to \
13471                     https://github.com/zed-industries/zed/issues/22692"
13472                );
13473            }
13474            self.request_autoscroll(Autoscroll::fit(), cx);
13475            self.unmark_text(window, cx);
13476            self.refresh_edit_prediction(true, false, window, cx);
13477            cx.emit(EditorEvent::Edited { transaction_id });
13478            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13479        }
13480    }
13481
13482    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13483        if self.read_only(cx) {
13484            return;
13485        }
13486
13487        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13488
13489        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13490            if let Some((_, Some(selections))) =
13491                self.selection_history.transaction(transaction_id).cloned()
13492            {
13493                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13494                    s.select_anchors(selections.to_vec());
13495                });
13496            } else {
13497                log::error!(
13498                    "No entry in selection_history found for redo. \
13499                     This may correspond to a bug where undo does not update the selection. \
13500                     If this is occurring, please add details to \
13501                     https://github.com/zed-industries/zed/issues/22692"
13502                );
13503            }
13504            self.request_autoscroll(Autoscroll::fit(), cx);
13505            self.unmark_text(window, cx);
13506            self.refresh_edit_prediction(true, false, window, cx);
13507            cx.emit(EditorEvent::Edited { transaction_id });
13508        }
13509    }
13510
13511    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13512        self.buffer
13513            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13514    }
13515
13516    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13517        self.buffer
13518            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13519    }
13520
13521    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13522        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13523        self.change_selections(Default::default(), window, cx, |s| {
13524            s.move_with(|map, selection| {
13525                let cursor = if selection.is_empty() {
13526                    movement::left(map, selection.start)
13527                } else {
13528                    selection.start
13529                };
13530                selection.collapse_to(cursor, SelectionGoal::None);
13531            });
13532        })
13533    }
13534
13535    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13536        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13537        self.change_selections(Default::default(), window, cx, |s| {
13538            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13539        })
13540    }
13541
13542    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13543        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13544        self.change_selections(Default::default(), window, cx, |s| {
13545            s.move_with(|map, selection| {
13546                let cursor = if selection.is_empty() {
13547                    movement::right(map, selection.end)
13548                } else {
13549                    selection.end
13550                };
13551                selection.collapse_to(cursor, SelectionGoal::None)
13552            });
13553        })
13554    }
13555
13556    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13557        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13558        self.change_selections(Default::default(), window, cx, |s| {
13559            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13560        });
13561    }
13562
13563    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13564        if self.take_rename(true, window, cx).is_some() {
13565            return;
13566        }
13567
13568        if self.mode.is_single_line() {
13569            cx.propagate();
13570            return;
13571        }
13572
13573        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13574
13575        let text_layout_details = &self.text_layout_details(window);
13576        let selection_count = self.selections.count();
13577        let first_selection = self.selections.first_anchor();
13578
13579        self.change_selections(Default::default(), window, cx, |s| {
13580            s.move_with(|map, selection| {
13581                if !selection.is_empty() {
13582                    selection.goal = SelectionGoal::None;
13583                }
13584                let (cursor, goal) = movement::up(
13585                    map,
13586                    selection.start,
13587                    selection.goal,
13588                    false,
13589                    text_layout_details,
13590                );
13591                selection.collapse_to(cursor, goal);
13592            });
13593        });
13594
13595        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13596        {
13597            cx.propagate();
13598        }
13599    }
13600
13601    pub fn move_up_by_lines(
13602        &mut self,
13603        action: &MoveUpByLines,
13604        window: &mut Window,
13605        cx: &mut Context<Self>,
13606    ) {
13607        if self.take_rename(true, window, cx).is_some() {
13608            return;
13609        }
13610
13611        if self.mode.is_single_line() {
13612            cx.propagate();
13613            return;
13614        }
13615
13616        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13617
13618        let text_layout_details = &self.text_layout_details(window);
13619
13620        self.change_selections(Default::default(), window, cx, |s| {
13621            s.move_with(|map, selection| {
13622                if !selection.is_empty() {
13623                    selection.goal = SelectionGoal::None;
13624                }
13625                let (cursor, goal) = movement::up_by_rows(
13626                    map,
13627                    selection.start,
13628                    action.lines,
13629                    selection.goal,
13630                    false,
13631                    text_layout_details,
13632                );
13633                selection.collapse_to(cursor, goal);
13634            });
13635        })
13636    }
13637
13638    pub fn move_down_by_lines(
13639        &mut self,
13640        action: &MoveDownByLines,
13641        window: &mut Window,
13642        cx: &mut Context<Self>,
13643    ) {
13644        if self.take_rename(true, window, cx).is_some() {
13645            return;
13646        }
13647
13648        if self.mode.is_single_line() {
13649            cx.propagate();
13650            return;
13651        }
13652
13653        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13654
13655        let text_layout_details = &self.text_layout_details(window);
13656
13657        self.change_selections(Default::default(), window, cx, |s| {
13658            s.move_with(|map, selection| {
13659                if !selection.is_empty() {
13660                    selection.goal = SelectionGoal::None;
13661                }
13662                let (cursor, goal) = movement::down_by_rows(
13663                    map,
13664                    selection.start,
13665                    action.lines,
13666                    selection.goal,
13667                    false,
13668                    text_layout_details,
13669                );
13670                selection.collapse_to(cursor, goal);
13671            });
13672        })
13673    }
13674
13675    pub fn select_down_by_lines(
13676        &mut self,
13677        action: &SelectDownByLines,
13678        window: &mut Window,
13679        cx: &mut Context<Self>,
13680    ) {
13681        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13682        let text_layout_details = &self.text_layout_details(window);
13683        self.change_selections(Default::default(), window, cx, |s| {
13684            s.move_heads_with(|map, head, goal| {
13685                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13686            })
13687        })
13688    }
13689
13690    pub fn select_up_by_lines(
13691        &mut self,
13692        action: &SelectUpByLines,
13693        window: &mut Window,
13694        cx: &mut Context<Self>,
13695    ) {
13696        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13697        let text_layout_details = &self.text_layout_details(window);
13698        self.change_selections(Default::default(), window, cx, |s| {
13699            s.move_heads_with(|map, head, goal| {
13700                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13701            })
13702        })
13703    }
13704
13705    pub fn select_page_up(
13706        &mut self,
13707        _: &SelectPageUp,
13708        window: &mut Window,
13709        cx: &mut Context<Self>,
13710    ) {
13711        let Some(row_count) = self.visible_row_count() else {
13712            return;
13713        };
13714
13715        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13716
13717        let text_layout_details = &self.text_layout_details(window);
13718
13719        self.change_selections(Default::default(), window, cx, |s| {
13720            s.move_heads_with(|map, head, goal| {
13721                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13722            })
13723        })
13724    }
13725
13726    pub fn move_page_up(
13727        &mut self,
13728        action: &MovePageUp,
13729        window: &mut Window,
13730        cx: &mut Context<Self>,
13731    ) {
13732        if self.take_rename(true, window, cx).is_some() {
13733            return;
13734        }
13735
13736        if self
13737            .context_menu
13738            .borrow_mut()
13739            .as_mut()
13740            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13741            .unwrap_or(false)
13742        {
13743            return;
13744        }
13745
13746        if matches!(self.mode, EditorMode::SingleLine) {
13747            cx.propagate();
13748            return;
13749        }
13750
13751        let Some(row_count) = self.visible_row_count() else {
13752            return;
13753        };
13754
13755        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13756
13757        let effects = if action.center_cursor {
13758            SelectionEffects::scroll(Autoscroll::center())
13759        } else {
13760            SelectionEffects::default()
13761        };
13762
13763        let text_layout_details = &self.text_layout_details(window);
13764
13765        self.change_selections(effects, window, cx, |s| {
13766            s.move_with(|map, selection| {
13767                if !selection.is_empty() {
13768                    selection.goal = SelectionGoal::None;
13769                }
13770                let (cursor, goal) = movement::up_by_rows(
13771                    map,
13772                    selection.end,
13773                    row_count,
13774                    selection.goal,
13775                    false,
13776                    text_layout_details,
13777                );
13778                selection.collapse_to(cursor, goal);
13779            });
13780        });
13781    }
13782
13783    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13784        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13785        let text_layout_details = &self.text_layout_details(window);
13786        self.change_selections(Default::default(), window, cx, |s| {
13787            s.move_heads_with(|map, head, goal| {
13788                movement::up(map, head, goal, false, text_layout_details)
13789            })
13790        })
13791    }
13792
13793    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13794        self.take_rename(true, window, cx);
13795
13796        if self.mode.is_single_line() {
13797            cx.propagate();
13798            return;
13799        }
13800
13801        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13802
13803        let text_layout_details = &self.text_layout_details(window);
13804        let selection_count = self.selections.count();
13805        let first_selection = self.selections.first_anchor();
13806
13807        self.change_selections(Default::default(), window, cx, |s| {
13808            s.move_with(|map, selection| {
13809                if !selection.is_empty() {
13810                    selection.goal = SelectionGoal::None;
13811                }
13812                let (cursor, goal) = movement::down(
13813                    map,
13814                    selection.end,
13815                    selection.goal,
13816                    false,
13817                    text_layout_details,
13818                );
13819                selection.collapse_to(cursor, goal);
13820            });
13821        });
13822
13823        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13824        {
13825            cx.propagate();
13826        }
13827    }
13828
13829    pub fn select_page_down(
13830        &mut self,
13831        _: &SelectPageDown,
13832        window: &mut Window,
13833        cx: &mut Context<Self>,
13834    ) {
13835        let Some(row_count) = self.visible_row_count() else {
13836            return;
13837        };
13838
13839        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13840
13841        let text_layout_details = &self.text_layout_details(window);
13842
13843        self.change_selections(Default::default(), window, cx, |s| {
13844            s.move_heads_with(|map, head, goal| {
13845                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13846            })
13847        })
13848    }
13849
13850    pub fn move_page_down(
13851        &mut self,
13852        action: &MovePageDown,
13853        window: &mut Window,
13854        cx: &mut Context<Self>,
13855    ) {
13856        if self.take_rename(true, window, cx).is_some() {
13857            return;
13858        }
13859
13860        if self
13861            .context_menu
13862            .borrow_mut()
13863            .as_mut()
13864            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13865            .unwrap_or(false)
13866        {
13867            return;
13868        }
13869
13870        if matches!(self.mode, EditorMode::SingleLine) {
13871            cx.propagate();
13872            return;
13873        }
13874
13875        let Some(row_count) = self.visible_row_count() else {
13876            return;
13877        };
13878
13879        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13880
13881        let effects = if action.center_cursor {
13882            SelectionEffects::scroll(Autoscroll::center())
13883        } else {
13884            SelectionEffects::default()
13885        };
13886
13887        let text_layout_details = &self.text_layout_details(window);
13888        self.change_selections(effects, window, cx, |s| {
13889            s.move_with(|map, selection| {
13890                if !selection.is_empty() {
13891                    selection.goal = SelectionGoal::None;
13892                }
13893                let (cursor, goal) = movement::down_by_rows(
13894                    map,
13895                    selection.end,
13896                    row_count,
13897                    selection.goal,
13898                    false,
13899                    text_layout_details,
13900                );
13901                selection.collapse_to(cursor, goal);
13902            });
13903        });
13904    }
13905
13906    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13907        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13908        let text_layout_details = &self.text_layout_details(window);
13909        self.change_selections(Default::default(), window, cx, |s| {
13910            s.move_heads_with(|map, head, goal| {
13911                movement::down(map, head, goal, false, text_layout_details)
13912            })
13913        });
13914    }
13915
13916    pub fn context_menu_first(
13917        &mut self,
13918        _: &ContextMenuFirst,
13919        window: &mut Window,
13920        cx: &mut Context<Self>,
13921    ) {
13922        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13923            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13924        }
13925    }
13926
13927    pub fn context_menu_prev(
13928        &mut self,
13929        _: &ContextMenuPrevious,
13930        window: &mut Window,
13931        cx: &mut Context<Self>,
13932    ) {
13933        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13934            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13935        }
13936    }
13937
13938    pub fn context_menu_next(
13939        &mut self,
13940        _: &ContextMenuNext,
13941        window: &mut Window,
13942        cx: &mut Context<Self>,
13943    ) {
13944        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13945            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13946        }
13947    }
13948
13949    pub fn context_menu_last(
13950        &mut self,
13951        _: &ContextMenuLast,
13952        window: &mut Window,
13953        cx: &mut Context<Self>,
13954    ) {
13955        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13956            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13957        }
13958    }
13959
13960    pub fn signature_help_prev(
13961        &mut self,
13962        _: &SignatureHelpPrevious,
13963        _: &mut Window,
13964        cx: &mut Context<Self>,
13965    ) {
13966        if let Some(popover) = self.signature_help_state.popover_mut() {
13967            if popover.current_signature == 0 {
13968                popover.current_signature = popover.signatures.len() - 1;
13969            } else {
13970                popover.current_signature -= 1;
13971            }
13972            cx.notify();
13973        }
13974    }
13975
13976    pub fn signature_help_next(
13977        &mut self,
13978        _: &SignatureHelpNext,
13979        _: &mut Window,
13980        cx: &mut Context<Self>,
13981    ) {
13982        if let Some(popover) = self.signature_help_state.popover_mut() {
13983            if popover.current_signature + 1 == popover.signatures.len() {
13984                popover.current_signature = 0;
13985            } else {
13986                popover.current_signature += 1;
13987            }
13988            cx.notify();
13989        }
13990    }
13991
13992    pub fn move_to_previous_word_start(
13993        &mut self,
13994        _: &MoveToPreviousWordStart,
13995        window: &mut Window,
13996        cx: &mut Context<Self>,
13997    ) {
13998        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13999        self.change_selections(Default::default(), window, cx, |s| {
14000            s.move_cursors_with(|map, head, _| {
14001                (
14002                    movement::previous_word_start(map, head),
14003                    SelectionGoal::None,
14004                )
14005            });
14006        })
14007    }
14008
14009    pub fn move_to_previous_subword_start(
14010        &mut self,
14011        _: &MoveToPreviousSubwordStart,
14012        window: &mut Window,
14013        cx: &mut Context<Self>,
14014    ) {
14015        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14016        self.change_selections(Default::default(), window, cx, |s| {
14017            s.move_cursors_with(|map, head, _| {
14018                (
14019                    movement::previous_subword_start(map, head),
14020                    SelectionGoal::None,
14021                )
14022            });
14023        })
14024    }
14025
14026    pub fn select_to_previous_word_start(
14027        &mut self,
14028        _: &SelectToPreviousWordStart,
14029        window: &mut Window,
14030        cx: &mut Context<Self>,
14031    ) {
14032        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14033        self.change_selections(Default::default(), window, cx, |s| {
14034            s.move_heads_with(|map, head, _| {
14035                (
14036                    movement::previous_word_start(map, head),
14037                    SelectionGoal::None,
14038                )
14039            });
14040        })
14041    }
14042
14043    pub fn select_to_previous_subword_start(
14044        &mut self,
14045        _: &SelectToPreviousSubwordStart,
14046        window: &mut Window,
14047        cx: &mut Context<Self>,
14048    ) {
14049        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14050        self.change_selections(Default::default(), window, cx, |s| {
14051            s.move_heads_with(|map, head, _| {
14052                (
14053                    movement::previous_subword_start(map, head),
14054                    SelectionGoal::None,
14055                )
14056            });
14057        })
14058    }
14059
14060    pub fn delete_to_previous_word_start(
14061        &mut self,
14062        action: &DeleteToPreviousWordStart,
14063        window: &mut Window,
14064        cx: &mut Context<Self>,
14065    ) {
14066        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14067        self.transact(window, cx, |this, window, cx| {
14068            this.select_autoclose_pair(window, cx);
14069            this.change_selections(Default::default(), window, cx, |s| {
14070                s.move_with(|map, selection| {
14071                    if selection.is_empty() {
14072                        let mut cursor = if action.ignore_newlines {
14073                            movement::previous_word_start(map, selection.head())
14074                        } else {
14075                            movement::previous_word_start_or_newline(map, selection.head())
14076                        };
14077                        cursor = movement::adjust_greedy_deletion(
14078                            map,
14079                            selection.head(),
14080                            cursor,
14081                            action.ignore_brackets,
14082                        );
14083                        selection.set_head(cursor, SelectionGoal::None);
14084                    }
14085                });
14086            });
14087            this.insert("", window, cx);
14088        });
14089    }
14090
14091    pub fn delete_to_previous_subword_start(
14092        &mut self,
14093        _: &DeleteToPreviousSubwordStart,
14094        window: &mut Window,
14095        cx: &mut Context<Self>,
14096    ) {
14097        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14098        self.transact(window, cx, |this, window, cx| {
14099            this.select_autoclose_pair(window, cx);
14100            this.change_selections(Default::default(), window, cx, |s| {
14101                s.move_with(|map, selection| {
14102                    if selection.is_empty() {
14103                        let mut cursor = movement::previous_subword_start(map, selection.head());
14104                        cursor =
14105                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14106                        selection.set_head(cursor, SelectionGoal::None);
14107                    }
14108                });
14109            });
14110            this.insert("", window, cx);
14111        });
14112    }
14113
14114    pub fn move_to_next_word_end(
14115        &mut self,
14116        _: &MoveToNextWordEnd,
14117        window: &mut Window,
14118        cx: &mut Context<Self>,
14119    ) {
14120        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14121        self.change_selections(Default::default(), window, cx, |s| {
14122            s.move_cursors_with(|map, head, _| {
14123                (movement::next_word_end(map, head), SelectionGoal::None)
14124            });
14125        })
14126    }
14127
14128    pub fn move_to_next_subword_end(
14129        &mut self,
14130        _: &MoveToNextSubwordEnd,
14131        window: &mut Window,
14132        cx: &mut Context<Self>,
14133    ) {
14134        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14135        self.change_selections(Default::default(), window, cx, |s| {
14136            s.move_cursors_with(|map, head, _| {
14137                (movement::next_subword_end(map, head), SelectionGoal::None)
14138            });
14139        })
14140    }
14141
14142    pub fn select_to_next_word_end(
14143        &mut self,
14144        _: &SelectToNextWordEnd,
14145        window: &mut Window,
14146        cx: &mut Context<Self>,
14147    ) {
14148        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14149        self.change_selections(Default::default(), window, cx, |s| {
14150            s.move_heads_with(|map, head, _| {
14151                (movement::next_word_end(map, head), SelectionGoal::None)
14152            });
14153        })
14154    }
14155
14156    pub fn select_to_next_subword_end(
14157        &mut self,
14158        _: &SelectToNextSubwordEnd,
14159        window: &mut Window,
14160        cx: &mut Context<Self>,
14161    ) {
14162        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14163        self.change_selections(Default::default(), window, cx, |s| {
14164            s.move_heads_with(|map, head, _| {
14165                (movement::next_subword_end(map, head), SelectionGoal::None)
14166            });
14167        })
14168    }
14169
14170    pub fn delete_to_next_word_end(
14171        &mut self,
14172        action: &DeleteToNextWordEnd,
14173        window: &mut Window,
14174        cx: &mut Context<Self>,
14175    ) {
14176        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14177        self.transact(window, cx, |this, window, cx| {
14178            this.change_selections(Default::default(), window, cx, |s| {
14179                s.move_with(|map, selection| {
14180                    if selection.is_empty() {
14181                        let mut cursor = if action.ignore_newlines {
14182                            movement::next_word_end(map, selection.head())
14183                        } else {
14184                            movement::next_word_end_or_newline(map, selection.head())
14185                        };
14186                        cursor = movement::adjust_greedy_deletion(
14187                            map,
14188                            selection.head(),
14189                            cursor,
14190                            action.ignore_brackets,
14191                        );
14192                        selection.set_head(cursor, SelectionGoal::None);
14193                    }
14194                });
14195            });
14196            this.insert("", window, cx);
14197        });
14198    }
14199
14200    pub fn delete_to_next_subword_end(
14201        &mut self,
14202        _: &DeleteToNextSubwordEnd,
14203        window: &mut Window,
14204        cx: &mut Context<Self>,
14205    ) {
14206        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14207        self.transact(window, cx, |this, window, cx| {
14208            this.change_selections(Default::default(), window, cx, |s| {
14209                s.move_with(|map, selection| {
14210                    if selection.is_empty() {
14211                        let mut cursor = movement::next_subword_end(map, selection.head());
14212                        cursor =
14213                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14214                        selection.set_head(cursor, SelectionGoal::None);
14215                    }
14216                });
14217            });
14218            this.insert("", window, cx);
14219        });
14220    }
14221
14222    pub fn move_to_beginning_of_line(
14223        &mut self,
14224        action: &MoveToBeginningOfLine,
14225        window: &mut Window,
14226        cx: &mut Context<Self>,
14227    ) {
14228        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14229        self.change_selections(Default::default(), window, cx, |s| {
14230            s.move_cursors_with(|map, head, _| {
14231                (
14232                    movement::indented_line_beginning(
14233                        map,
14234                        head,
14235                        action.stop_at_soft_wraps,
14236                        action.stop_at_indent,
14237                    ),
14238                    SelectionGoal::None,
14239                )
14240            });
14241        })
14242    }
14243
14244    pub fn select_to_beginning_of_line(
14245        &mut self,
14246        action: &SelectToBeginningOfLine,
14247        window: &mut Window,
14248        cx: &mut Context<Self>,
14249    ) {
14250        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14251        self.change_selections(Default::default(), window, cx, |s| {
14252            s.move_heads_with(|map, head, _| {
14253                (
14254                    movement::indented_line_beginning(
14255                        map,
14256                        head,
14257                        action.stop_at_soft_wraps,
14258                        action.stop_at_indent,
14259                    ),
14260                    SelectionGoal::None,
14261                )
14262            });
14263        });
14264    }
14265
14266    pub fn delete_to_beginning_of_line(
14267        &mut self,
14268        action: &DeleteToBeginningOfLine,
14269        window: &mut Window,
14270        cx: &mut Context<Self>,
14271    ) {
14272        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14273        self.transact(window, cx, |this, window, cx| {
14274            this.change_selections(Default::default(), window, cx, |s| {
14275                s.move_with(|_, selection| {
14276                    selection.reversed = true;
14277                });
14278            });
14279
14280            this.select_to_beginning_of_line(
14281                &SelectToBeginningOfLine {
14282                    stop_at_soft_wraps: false,
14283                    stop_at_indent: action.stop_at_indent,
14284                },
14285                window,
14286                cx,
14287            );
14288            this.backspace(&Backspace, window, cx);
14289        });
14290    }
14291
14292    pub fn move_to_end_of_line(
14293        &mut self,
14294        action: &MoveToEndOfLine,
14295        window: &mut Window,
14296        cx: &mut Context<Self>,
14297    ) {
14298        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14299        self.change_selections(Default::default(), window, cx, |s| {
14300            s.move_cursors_with(|map, head, _| {
14301                (
14302                    movement::line_end(map, head, action.stop_at_soft_wraps),
14303                    SelectionGoal::None,
14304                )
14305            });
14306        })
14307    }
14308
14309    pub fn select_to_end_of_line(
14310        &mut self,
14311        action: &SelectToEndOfLine,
14312        window: &mut Window,
14313        cx: &mut Context<Self>,
14314    ) {
14315        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14316        self.change_selections(Default::default(), window, cx, |s| {
14317            s.move_heads_with(|map, head, _| {
14318                (
14319                    movement::line_end(map, head, action.stop_at_soft_wraps),
14320                    SelectionGoal::None,
14321                )
14322            });
14323        })
14324    }
14325
14326    pub fn delete_to_end_of_line(
14327        &mut self,
14328        _: &DeleteToEndOfLine,
14329        window: &mut Window,
14330        cx: &mut Context<Self>,
14331    ) {
14332        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14333        self.transact(window, cx, |this, window, cx| {
14334            this.select_to_end_of_line(
14335                &SelectToEndOfLine {
14336                    stop_at_soft_wraps: false,
14337                },
14338                window,
14339                cx,
14340            );
14341            this.delete(&Delete, window, cx);
14342        });
14343    }
14344
14345    pub fn cut_to_end_of_line(
14346        &mut self,
14347        action: &CutToEndOfLine,
14348        window: &mut Window,
14349        cx: &mut Context<Self>,
14350    ) {
14351        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14352        self.transact(window, cx, |this, window, cx| {
14353            this.select_to_end_of_line(
14354                &SelectToEndOfLine {
14355                    stop_at_soft_wraps: false,
14356                },
14357                window,
14358                cx,
14359            );
14360            if !action.stop_at_newlines {
14361                this.change_selections(Default::default(), window, cx, |s| {
14362                    s.move_with(|_, sel| {
14363                        if sel.is_empty() {
14364                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14365                        }
14366                    });
14367                });
14368            }
14369            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14370            let item = this.cut_common(false, window, cx);
14371            cx.write_to_clipboard(item);
14372        });
14373    }
14374
14375    pub fn move_to_start_of_paragraph(
14376        &mut self,
14377        _: &MoveToStartOfParagraph,
14378        window: &mut Window,
14379        cx: &mut Context<Self>,
14380    ) {
14381        if matches!(self.mode, EditorMode::SingleLine) {
14382            cx.propagate();
14383            return;
14384        }
14385        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14386        self.change_selections(Default::default(), window, cx, |s| {
14387            s.move_with(|map, selection| {
14388                selection.collapse_to(
14389                    movement::start_of_paragraph(map, selection.head(), 1),
14390                    SelectionGoal::None,
14391                )
14392            });
14393        })
14394    }
14395
14396    pub fn move_to_end_of_paragraph(
14397        &mut self,
14398        _: &MoveToEndOfParagraph,
14399        window: &mut Window,
14400        cx: &mut Context<Self>,
14401    ) {
14402        if matches!(self.mode, EditorMode::SingleLine) {
14403            cx.propagate();
14404            return;
14405        }
14406        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14407        self.change_selections(Default::default(), window, cx, |s| {
14408            s.move_with(|map, selection| {
14409                selection.collapse_to(
14410                    movement::end_of_paragraph(map, selection.head(), 1),
14411                    SelectionGoal::None,
14412                )
14413            });
14414        })
14415    }
14416
14417    pub fn select_to_start_of_paragraph(
14418        &mut self,
14419        _: &SelectToStartOfParagraph,
14420        window: &mut Window,
14421        cx: &mut Context<Self>,
14422    ) {
14423        if matches!(self.mode, EditorMode::SingleLine) {
14424            cx.propagate();
14425            return;
14426        }
14427        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14428        self.change_selections(Default::default(), window, cx, |s| {
14429            s.move_heads_with(|map, head, _| {
14430                (
14431                    movement::start_of_paragraph(map, head, 1),
14432                    SelectionGoal::None,
14433                )
14434            });
14435        })
14436    }
14437
14438    pub fn select_to_end_of_paragraph(
14439        &mut self,
14440        _: &SelectToEndOfParagraph,
14441        window: &mut Window,
14442        cx: &mut Context<Self>,
14443    ) {
14444        if matches!(self.mode, EditorMode::SingleLine) {
14445            cx.propagate();
14446            return;
14447        }
14448        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14449        self.change_selections(Default::default(), window, cx, |s| {
14450            s.move_heads_with(|map, head, _| {
14451                (
14452                    movement::end_of_paragraph(map, head, 1),
14453                    SelectionGoal::None,
14454                )
14455            });
14456        })
14457    }
14458
14459    pub fn move_to_start_of_excerpt(
14460        &mut self,
14461        _: &MoveToStartOfExcerpt,
14462        window: &mut Window,
14463        cx: &mut Context<Self>,
14464    ) {
14465        if matches!(self.mode, EditorMode::SingleLine) {
14466            cx.propagate();
14467            return;
14468        }
14469        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14470        self.change_selections(Default::default(), window, cx, |s| {
14471            s.move_with(|map, selection| {
14472                selection.collapse_to(
14473                    movement::start_of_excerpt(
14474                        map,
14475                        selection.head(),
14476                        workspace::searchable::Direction::Prev,
14477                    ),
14478                    SelectionGoal::None,
14479                )
14480            });
14481        })
14482    }
14483
14484    pub fn move_to_start_of_next_excerpt(
14485        &mut self,
14486        _: &MoveToStartOfNextExcerpt,
14487        window: &mut Window,
14488        cx: &mut Context<Self>,
14489    ) {
14490        if matches!(self.mode, EditorMode::SingleLine) {
14491            cx.propagate();
14492            return;
14493        }
14494
14495        self.change_selections(Default::default(), window, cx, |s| {
14496            s.move_with(|map, selection| {
14497                selection.collapse_to(
14498                    movement::start_of_excerpt(
14499                        map,
14500                        selection.head(),
14501                        workspace::searchable::Direction::Next,
14502                    ),
14503                    SelectionGoal::None,
14504                )
14505            });
14506        })
14507    }
14508
14509    pub fn move_to_end_of_excerpt(
14510        &mut self,
14511        _: &MoveToEndOfExcerpt,
14512        window: &mut Window,
14513        cx: &mut Context<Self>,
14514    ) {
14515        if matches!(self.mode, EditorMode::SingleLine) {
14516            cx.propagate();
14517            return;
14518        }
14519        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14520        self.change_selections(Default::default(), window, cx, |s| {
14521            s.move_with(|map, selection| {
14522                selection.collapse_to(
14523                    movement::end_of_excerpt(
14524                        map,
14525                        selection.head(),
14526                        workspace::searchable::Direction::Next,
14527                    ),
14528                    SelectionGoal::None,
14529                )
14530            });
14531        })
14532    }
14533
14534    pub fn move_to_end_of_previous_excerpt(
14535        &mut self,
14536        _: &MoveToEndOfPreviousExcerpt,
14537        window: &mut Window,
14538        cx: &mut Context<Self>,
14539    ) {
14540        if matches!(self.mode, EditorMode::SingleLine) {
14541            cx.propagate();
14542            return;
14543        }
14544        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14545        self.change_selections(Default::default(), window, cx, |s| {
14546            s.move_with(|map, selection| {
14547                selection.collapse_to(
14548                    movement::end_of_excerpt(
14549                        map,
14550                        selection.head(),
14551                        workspace::searchable::Direction::Prev,
14552                    ),
14553                    SelectionGoal::None,
14554                )
14555            });
14556        })
14557    }
14558
14559    pub fn select_to_start_of_excerpt(
14560        &mut self,
14561        _: &SelectToStartOfExcerpt,
14562        window: &mut Window,
14563        cx: &mut Context<Self>,
14564    ) {
14565        if matches!(self.mode, EditorMode::SingleLine) {
14566            cx.propagate();
14567            return;
14568        }
14569        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14570        self.change_selections(Default::default(), window, cx, |s| {
14571            s.move_heads_with(|map, head, _| {
14572                (
14573                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14574                    SelectionGoal::None,
14575                )
14576            });
14577        })
14578    }
14579
14580    pub fn select_to_start_of_next_excerpt(
14581        &mut self,
14582        _: &SelectToStartOfNextExcerpt,
14583        window: &mut Window,
14584        cx: &mut Context<Self>,
14585    ) {
14586        if matches!(self.mode, EditorMode::SingleLine) {
14587            cx.propagate();
14588            return;
14589        }
14590        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14591        self.change_selections(Default::default(), window, cx, |s| {
14592            s.move_heads_with(|map, head, _| {
14593                (
14594                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14595                    SelectionGoal::None,
14596                )
14597            });
14598        })
14599    }
14600
14601    pub fn select_to_end_of_excerpt(
14602        &mut self,
14603        _: &SelectToEndOfExcerpt,
14604        window: &mut Window,
14605        cx: &mut Context<Self>,
14606    ) {
14607        if matches!(self.mode, EditorMode::SingleLine) {
14608            cx.propagate();
14609            return;
14610        }
14611        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14612        self.change_selections(Default::default(), window, cx, |s| {
14613            s.move_heads_with(|map, head, _| {
14614                (
14615                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14616                    SelectionGoal::None,
14617                )
14618            });
14619        })
14620    }
14621
14622    pub fn select_to_end_of_previous_excerpt(
14623        &mut self,
14624        _: &SelectToEndOfPreviousExcerpt,
14625        window: &mut Window,
14626        cx: &mut Context<Self>,
14627    ) {
14628        if matches!(self.mode, EditorMode::SingleLine) {
14629            cx.propagate();
14630            return;
14631        }
14632        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14633        self.change_selections(Default::default(), window, cx, |s| {
14634            s.move_heads_with(|map, head, _| {
14635                (
14636                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14637                    SelectionGoal::None,
14638                )
14639            });
14640        })
14641    }
14642
14643    pub fn move_to_beginning(
14644        &mut self,
14645        _: &MoveToBeginning,
14646        window: &mut Window,
14647        cx: &mut Context<Self>,
14648    ) {
14649        if matches!(self.mode, EditorMode::SingleLine) {
14650            cx.propagate();
14651            return;
14652        }
14653        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14654        self.change_selections(Default::default(), window, cx, |s| {
14655            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14656        });
14657    }
14658
14659    pub fn select_to_beginning(
14660        &mut self,
14661        _: &SelectToBeginning,
14662        window: &mut Window,
14663        cx: &mut Context<Self>,
14664    ) {
14665        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14666        selection.set_head(Point::zero(), SelectionGoal::None);
14667        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14668        self.change_selections(Default::default(), window, cx, |s| {
14669            s.select(vec![selection]);
14670        });
14671    }
14672
14673    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14674        if matches!(self.mode, EditorMode::SingleLine) {
14675            cx.propagate();
14676            return;
14677        }
14678        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14679        let cursor = self.buffer.read(cx).read(cx).len();
14680        self.change_selections(Default::default(), window, cx, |s| {
14681            s.select_ranges(vec![cursor..cursor])
14682        });
14683    }
14684
14685    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14686        self.nav_history = nav_history;
14687    }
14688
14689    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14690        self.nav_history.as_ref()
14691    }
14692
14693    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14694        self.push_to_nav_history(
14695            self.selections.newest_anchor().head(),
14696            None,
14697            false,
14698            true,
14699            cx,
14700        );
14701    }
14702
14703    fn push_to_nav_history(
14704        &mut self,
14705        cursor_anchor: Anchor,
14706        new_position: Option<Point>,
14707        is_deactivate: bool,
14708        always: bool,
14709        cx: &mut Context<Self>,
14710    ) {
14711        if let Some(nav_history) = self.nav_history.as_mut() {
14712            let buffer = self.buffer.read(cx).read(cx);
14713            let cursor_position = cursor_anchor.to_point(&buffer);
14714            let scroll_state = self.scroll_manager.anchor();
14715            let scroll_top_row = scroll_state.top_row(&buffer);
14716            drop(buffer);
14717
14718            if let Some(new_position) = new_position {
14719                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14720                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14721                    return;
14722                }
14723            }
14724
14725            nav_history.push(
14726                Some(NavigationData {
14727                    cursor_anchor,
14728                    cursor_position,
14729                    scroll_anchor: scroll_state,
14730                    scroll_top_row,
14731                }),
14732                cx,
14733            );
14734            cx.emit(EditorEvent::PushedToNavHistory {
14735                anchor: cursor_anchor,
14736                is_deactivate,
14737            })
14738        }
14739    }
14740
14741    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14742        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14743        let buffer = self.buffer.read(cx).snapshot(cx);
14744        let mut selection = self
14745            .selections
14746            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14747        selection.set_head(buffer.len(), SelectionGoal::None);
14748        self.change_selections(Default::default(), window, cx, |s| {
14749            s.select(vec![selection]);
14750        });
14751    }
14752
14753    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14754        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14755        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14756            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14757        });
14758    }
14759
14760    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14761        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14762        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14763        let mut selections = self.selections.all::<Point>(&display_map);
14764        let max_point = display_map.buffer_snapshot().max_point();
14765        for selection in &mut selections {
14766            let rows = selection.spanned_rows(true, &display_map);
14767            selection.start = Point::new(rows.start.0, 0);
14768            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14769            selection.reversed = false;
14770        }
14771        self.change_selections(Default::default(), window, cx, |s| {
14772            s.select(selections);
14773        });
14774    }
14775
14776    pub fn split_selection_into_lines(
14777        &mut self,
14778        action: &SplitSelectionIntoLines,
14779        window: &mut Window,
14780        cx: &mut Context<Self>,
14781    ) {
14782        let selections = self
14783            .selections
14784            .all::<Point>(&self.display_snapshot(cx))
14785            .into_iter()
14786            .map(|selection| selection.start..selection.end)
14787            .collect::<Vec<_>>();
14788        self.unfold_ranges(&selections, true, true, cx);
14789
14790        let mut new_selection_ranges = Vec::new();
14791        {
14792            let buffer = self.buffer.read(cx).read(cx);
14793            for selection in selections {
14794                for row in selection.start.row..selection.end.row {
14795                    let line_start = Point::new(row, 0);
14796                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14797
14798                    if action.keep_selections {
14799                        // Keep the selection range for each line
14800                        let selection_start = if row == selection.start.row {
14801                            selection.start
14802                        } else {
14803                            line_start
14804                        };
14805                        new_selection_ranges.push(selection_start..line_end);
14806                    } else {
14807                        // Collapse to cursor at end of line
14808                        new_selection_ranges.push(line_end..line_end);
14809                    }
14810                }
14811
14812                let is_multiline_selection = selection.start.row != selection.end.row;
14813                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14814                // so this action feels more ergonomic when paired with other selection operations
14815                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14816                if !should_skip_last {
14817                    if action.keep_selections {
14818                        if is_multiline_selection {
14819                            let line_start = Point::new(selection.end.row, 0);
14820                            new_selection_ranges.push(line_start..selection.end);
14821                        } else {
14822                            new_selection_ranges.push(selection.start..selection.end);
14823                        }
14824                    } else {
14825                        new_selection_ranges.push(selection.end..selection.end);
14826                    }
14827                }
14828            }
14829        }
14830        self.change_selections(Default::default(), window, cx, |s| {
14831            s.select_ranges(new_selection_ranges);
14832        });
14833    }
14834
14835    pub fn add_selection_above(
14836        &mut self,
14837        action: &AddSelectionAbove,
14838        window: &mut Window,
14839        cx: &mut Context<Self>,
14840    ) {
14841        self.add_selection(true, action.skip_soft_wrap, window, cx);
14842    }
14843
14844    pub fn add_selection_below(
14845        &mut self,
14846        action: &AddSelectionBelow,
14847        window: &mut Window,
14848        cx: &mut Context<Self>,
14849    ) {
14850        self.add_selection(false, action.skip_soft_wrap, window, cx);
14851    }
14852
14853    fn add_selection(
14854        &mut self,
14855        above: bool,
14856        skip_soft_wrap: bool,
14857        window: &mut Window,
14858        cx: &mut Context<Self>,
14859    ) {
14860        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14861
14862        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14863        let all_selections = self.selections.all::<Point>(&display_map);
14864        let text_layout_details = self.text_layout_details(window);
14865
14866        let (mut columnar_selections, new_selections_to_columnarize) = {
14867            if let Some(state) = self.add_selections_state.as_ref() {
14868                let columnar_selection_ids: HashSet<_> = state
14869                    .groups
14870                    .iter()
14871                    .flat_map(|group| group.stack.iter())
14872                    .copied()
14873                    .collect();
14874
14875                all_selections
14876                    .into_iter()
14877                    .partition(|s| columnar_selection_ids.contains(&s.id))
14878            } else {
14879                (Vec::new(), all_selections)
14880            }
14881        };
14882
14883        let mut state = self
14884            .add_selections_state
14885            .take()
14886            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14887
14888        for selection in new_selections_to_columnarize {
14889            let range = selection.display_range(&display_map).sorted();
14890            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14891            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14892            let positions = start_x.min(end_x)..start_x.max(end_x);
14893            let mut stack = Vec::new();
14894            for row in range.start.row().0..=range.end.row().0 {
14895                if let Some(selection) = self.selections.build_columnar_selection(
14896                    &display_map,
14897                    DisplayRow(row),
14898                    &positions,
14899                    selection.reversed,
14900                    &text_layout_details,
14901                ) {
14902                    stack.push(selection.id);
14903                    columnar_selections.push(selection);
14904                }
14905            }
14906            if !stack.is_empty() {
14907                if above {
14908                    stack.reverse();
14909                }
14910                state.groups.push(AddSelectionsGroup { above, stack });
14911            }
14912        }
14913
14914        let mut final_selections = Vec::new();
14915        let end_row = if above {
14916            DisplayRow(0)
14917        } else {
14918            display_map.max_point().row()
14919        };
14920
14921        let mut last_added_item_per_group = HashMap::default();
14922        for group in state.groups.iter_mut() {
14923            if let Some(last_id) = group.stack.last() {
14924                last_added_item_per_group.insert(*last_id, group);
14925            }
14926        }
14927
14928        for selection in columnar_selections {
14929            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14930                if above == group.above {
14931                    let range = selection.display_range(&display_map).sorted();
14932                    debug_assert_eq!(range.start.row(), range.end.row());
14933                    let mut row = range.start.row();
14934                    let positions =
14935                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14936                            Pixels::from(start)..Pixels::from(end)
14937                        } else {
14938                            let start_x =
14939                                display_map.x_for_display_point(range.start, &text_layout_details);
14940                            let end_x =
14941                                display_map.x_for_display_point(range.end, &text_layout_details);
14942                            start_x.min(end_x)..start_x.max(end_x)
14943                        };
14944
14945                    let mut maybe_new_selection = None;
14946                    let direction = if above { -1 } else { 1 };
14947
14948                    while row != end_row {
14949                        if skip_soft_wrap {
14950                            row = display_map
14951                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14952                                .row();
14953                        } else if above {
14954                            row.0 -= 1;
14955                        } else {
14956                            row.0 += 1;
14957                        }
14958
14959                        if let Some(new_selection) = self.selections.build_columnar_selection(
14960                            &display_map,
14961                            row,
14962                            &positions,
14963                            selection.reversed,
14964                            &text_layout_details,
14965                        ) {
14966                            maybe_new_selection = Some(new_selection);
14967                            break;
14968                        }
14969                    }
14970
14971                    if let Some(new_selection) = maybe_new_selection {
14972                        group.stack.push(new_selection.id);
14973                        if above {
14974                            final_selections.push(new_selection);
14975                            final_selections.push(selection);
14976                        } else {
14977                            final_selections.push(selection);
14978                            final_selections.push(new_selection);
14979                        }
14980                    } else {
14981                        final_selections.push(selection);
14982                    }
14983                } else {
14984                    group.stack.pop();
14985                }
14986            } else {
14987                final_selections.push(selection);
14988            }
14989        }
14990
14991        self.change_selections(Default::default(), window, cx, |s| {
14992            s.select(final_selections);
14993        });
14994
14995        let final_selection_ids: HashSet<_> = self
14996            .selections
14997            .all::<Point>(&display_map)
14998            .iter()
14999            .map(|s| s.id)
15000            .collect();
15001        state.groups.retain_mut(|group| {
15002            // selections might get merged above so we remove invalid items from stacks
15003            group.stack.retain(|id| final_selection_ids.contains(id));
15004
15005            // single selection in stack can be treated as initial state
15006            group.stack.len() > 1
15007        });
15008
15009        if !state.groups.is_empty() {
15010            self.add_selections_state = Some(state);
15011        }
15012    }
15013
15014    pub fn insert_snippet_at_selections(
15015        &mut self,
15016        action: &InsertSnippet,
15017        window: &mut Window,
15018        cx: &mut Context<Self>,
15019    ) {
15020        self.try_insert_snippet_at_selections(action, window, cx)
15021            .log_err();
15022    }
15023
15024    fn try_insert_snippet_at_selections(
15025        &mut self,
15026        action: &InsertSnippet,
15027        window: &mut Window,
15028        cx: &mut Context<Self>,
15029    ) -> Result<()> {
15030        let insertion_ranges = self
15031            .selections
15032            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15033            .into_iter()
15034            .map(|selection| selection.range())
15035            .collect_vec();
15036
15037        let snippet = if let Some(snippet_body) = &action.snippet {
15038            if action.language.is_none() && action.name.is_none() {
15039                Snippet::parse(snippet_body)?
15040            } else {
15041                bail!("`snippet` is mutually exclusive with `language` and `name`")
15042            }
15043        } else if let Some(name) = &action.name {
15044            let project = self.project().context("no project")?;
15045            let snippet_store = project.read(cx).snippets().read(cx);
15046            let snippet = snippet_store
15047                .snippets_for(action.language.clone(), cx)
15048                .into_iter()
15049                .find(|snippet| snippet.name == *name)
15050                .context("snippet not found")?;
15051            Snippet::parse(&snippet.body)?
15052        } else {
15053            // todo(andrew): open modal to select snippet
15054            bail!("`name` or `snippet` is required")
15055        };
15056
15057        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15058    }
15059
15060    fn select_match_ranges(
15061        &mut self,
15062        range: Range<MultiBufferOffset>,
15063        reversed: bool,
15064        replace_newest: bool,
15065        auto_scroll: Option<Autoscroll>,
15066        window: &mut Window,
15067        cx: &mut Context<Editor>,
15068    ) {
15069        self.unfold_ranges(
15070            std::slice::from_ref(&range),
15071            false,
15072            auto_scroll.is_some(),
15073            cx,
15074        );
15075        let effects = if let Some(scroll) = auto_scroll {
15076            SelectionEffects::scroll(scroll)
15077        } else {
15078            SelectionEffects::no_scroll()
15079        };
15080        self.change_selections(effects, window, cx, |s| {
15081            if replace_newest {
15082                s.delete(s.newest_anchor().id);
15083            }
15084            if reversed {
15085                s.insert_range(range.end..range.start);
15086            } else {
15087                s.insert_range(range);
15088            }
15089        });
15090    }
15091
15092    pub fn select_next_match_internal(
15093        &mut self,
15094        display_map: &DisplaySnapshot,
15095        replace_newest: bool,
15096        autoscroll: Option<Autoscroll>,
15097        window: &mut Window,
15098        cx: &mut Context<Self>,
15099    ) -> Result<()> {
15100        let buffer = display_map.buffer_snapshot();
15101        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15102        if let Some(mut select_next_state) = self.select_next_state.take() {
15103            let query = &select_next_state.query;
15104            if !select_next_state.done {
15105                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15106                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15107                let mut next_selected_range = None;
15108
15109                let bytes_after_last_selection =
15110                    buffer.bytes_in_range(last_selection.end..buffer.len());
15111                let bytes_before_first_selection =
15112                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15113                let query_matches = query
15114                    .stream_find_iter(bytes_after_last_selection)
15115                    .map(|result| (last_selection.end, result))
15116                    .chain(
15117                        query
15118                            .stream_find_iter(bytes_before_first_selection)
15119                            .map(|result| (MultiBufferOffset(0), result)),
15120                    );
15121
15122                for (start_offset, query_match) in query_matches {
15123                    let query_match = query_match.unwrap(); // can only fail due to I/O
15124                    let offset_range =
15125                        start_offset + query_match.start()..start_offset + query_match.end();
15126
15127                    if !select_next_state.wordwise
15128                        || (!buffer.is_inside_word(offset_range.start, None)
15129                            && !buffer.is_inside_word(offset_range.end, None))
15130                    {
15131                        let idx = selections
15132                            .partition_point(|selection| selection.end <= offset_range.start);
15133                        let overlaps = selections
15134                            .get(idx)
15135                            .map_or(false, |selection| selection.start < offset_range.end);
15136
15137                        if !overlaps {
15138                            next_selected_range = Some(offset_range);
15139                            break;
15140                        }
15141                    }
15142                }
15143
15144                if let Some(next_selected_range) = next_selected_range {
15145                    self.select_match_ranges(
15146                        next_selected_range,
15147                        last_selection.reversed,
15148                        replace_newest,
15149                        autoscroll,
15150                        window,
15151                        cx,
15152                    );
15153                } else {
15154                    select_next_state.done = true;
15155                }
15156            }
15157
15158            self.select_next_state = Some(select_next_state);
15159        } else {
15160            let mut only_carets = true;
15161            let mut same_text_selected = true;
15162            let mut selected_text = None;
15163
15164            let mut selections_iter = selections.iter().peekable();
15165            while let Some(selection) = selections_iter.next() {
15166                if selection.start != selection.end {
15167                    only_carets = false;
15168                }
15169
15170                if same_text_selected {
15171                    if selected_text.is_none() {
15172                        selected_text =
15173                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15174                    }
15175
15176                    if let Some(next_selection) = selections_iter.peek() {
15177                        if next_selection.len() == selection.len() {
15178                            let next_selected_text = buffer
15179                                .text_for_range(next_selection.range())
15180                                .collect::<String>();
15181                            if Some(next_selected_text) != selected_text {
15182                                same_text_selected = false;
15183                                selected_text = None;
15184                            }
15185                        } else {
15186                            same_text_selected = false;
15187                            selected_text = None;
15188                        }
15189                    }
15190                }
15191            }
15192
15193            if only_carets {
15194                for selection in &mut selections {
15195                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15196                    selection.start = word_range.start;
15197                    selection.end = word_range.end;
15198                    selection.goal = SelectionGoal::None;
15199                    selection.reversed = false;
15200                    self.select_match_ranges(
15201                        selection.start..selection.end,
15202                        selection.reversed,
15203                        replace_newest,
15204                        autoscroll,
15205                        window,
15206                        cx,
15207                    );
15208                }
15209
15210                if selections.len() == 1 {
15211                    let selection = selections
15212                        .last()
15213                        .expect("ensured that there's only one selection");
15214                    let query = buffer
15215                        .text_for_range(selection.start..selection.end)
15216                        .collect::<String>();
15217                    let is_empty = query.is_empty();
15218                    let select_state = SelectNextState {
15219                        query: self.build_query(&[query], cx)?,
15220                        wordwise: true,
15221                        done: is_empty,
15222                    };
15223                    self.select_next_state = Some(select_state);
15224                } else {
15225                    self.select_next_state = None;
15226                }
15227            } else if let Some(selected_text) = selected_text {
15228                self.select_next_state = Some(SelectNextState {
15229                    query: self.build_query(&[selected_text], cx)?,
15230                    wordwise: false,
15231                    done: false,
15232                });
15233                self.select_next_match_internal(
15234                    display_map,
15235                    replace_newest,
15236                    autoscroll,
15237                    window,
15238                    cx,
15239                )?;
15240            }
15241        }
15242        Ok(())
15243    }
15244
15245    pub fn select_all_matches(
15246        &mut self,
15247        _action: &SelectAllMatches,
15248        window: &mut Window,
15249        cx: &mut Context<Self>,
15250    ) -> Result<()> {
15251        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15252
15253        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15254
15255        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15256        let Some(select_next_state) = self.select_next_state.as_mut() else {
15257            return Ok(());
15258        };
15259        if select_next_state.done {
15260            return Ok(());
15261        }
15262
15263        let mut new_selections = Vec::new();
15264
15265        let reversed = self
15266            .selections
15267            .oldest::<MultiBufferOffset>(&display_map)
15268            .reversed;
15269        let buffer = display_map.buffer_snapshot();
15270        let query_matches = select_next_state
15271            .query
15272            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15273
15274        for query_match in query_matches.into_iter() {
15275            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15276            let offset_range = if reversed {
15277                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15278            } else {
15279                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15280            };
15281
15282            if !select_next_state.wordwise
15283                || (!buffer.is_inside_word(offset_range.start, None)
15284                    && !buffer.is_inside_word(offset_range.end, None))
15285            {
15286                new_selections.push(offset_range.start..offset_range.end);
15287            }
15288        }
15289
15290        select_next_state.done = true;
15291
15292        if new_selections.is_empty() {
15293            log::error!("bug: new_selections is empty in select_all_matches");
15294            return Ok(());
15295        }
15296
15297        self.unfold_ranges(&new_selections.clone(), false, false, cx);
15298        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15299            selections.select_ranges(new_selections)
15300        });
15301
15302        Ok(())
15303    }
15304
15305    pub fn select_next(
15306        &mut self,
15307        action: &SelectNext,
15308        window: &mut Window,
15309        cx: &mut Context<Self>,
15310    ) -> Result<()> {
15311        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15312        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15313        self.select_next_match_internal(
15314            &display_map,
15315            action.replace_newest,
15316            Some(Autoscroll::newest()),
15317            window,
15318            cx,
15319        )?;
15320        Ok(())
15321    }
15322
15323    pub fn select_previous(
15324        &mut self,
15325        action: &SelectPrevious,
15326        window: &mut Window,
15327        cx: &mut Context<Self>,
15328    ) -> Result<()> {
15329        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15330        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15331        let buffer = display_map.buffer_snapshot();
15332        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15333        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15334            let query = &select_prev_state.query;
15335            if !select_prev_state.done {
15336                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15337                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15338                let mut next_selected_range = None;
15339                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15340                let bytes_before_last_selection =
15341                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15342                let bytes_after_first_selection =
15343                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15344                let query_matches = query
15345                    .stream_find_iter(bytes_before_last_selection)
15346                    .map(|result| (last_selection.start, result))
15347                    .chain(
15348                        query
15349                            .stream_find_iter(bytes_after_first_selection)
15350                            .map(|result| (buffer.len(), result)),
15351                    );
15352                for (end_offset, query_match) in query_matches {
15353                    let query_match = query_match.unwrap(); // can only fail due to I/O
15354                    let offset_range =
15355                        end_offset - query_match.end()..end_offset - query_match.start();
15356
15357                    if !select_prev_state.wordwise
15358                        || (!buffer.is_inside_word(offset_range.start, None)
15359                            && !buffer.is_inside_word(offset_range.end, None))
15360                    {
15361                        next_selected_range = Some(offset_range);
15362                        break;
15363                    }
15364                }
15365
15366                if let Some(next_selected_range) = next_selected_range {
15367                    self.select_match_ranges(
15368                        next_selected_range,
15369                        last_selection.reversed,
15370                        action.replace_newest,
15371                        Some(Autoscroll::newest()),
15372                        window,
15373                        cx,
15374                    );
15375                } else {
15376                    select_prev_state.done = true;
15377                }
15378            }
15379
15380            self.select_prev_state = Some(select_prev_state);
15381        } else {
15382            let mut only_carets = true;
15383            let mut same_text_selected = true;
15384            let mut selected_text = None;
15385
15386            let mut selections_iter = selections.iter().peekable();
15387            while let Some(selection) = selections_iter.next() {
15388                if selection.start != selection.end {
15389                    only_carets = false;
15390                }
15391
15392                if same_text_selected {
15393                    if selected_text.is_none() {
15394                        selected_text =
15395                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15396                    }
15397
15398                    if let Some(next_selection) = selections_iter.peek() {
15399                        if next_selection.len() == selection.len() {
15400                            let next_selected_text = buffer
15401                                .text_for_range(next_selection.range())
15402                                .collect::<String>();
15403                            if Some(next_selected_text) != selected_text {
15404                                same_text_selected = false;
15405                                selected_text = None;
15406                            }
15407                        } else {
15408                            same_text_selected = false;
15409                            selected_text = None;
15410                        }
15411                    }
15412                }
15413            }
15414
15415            if only_carets {
15416                for selection in &mut selections {
15417                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15418                    selection.start = word_range.start;
15419                    selection.end = word_range.end;
15420                    selection.goal = SelectionGoal::None;
15421                    selection.reversed = false;
15422                    self.select_match_ranges(
15423                        selection.start..selection.end,
15424                        selection.reversed,
15425                        action.replace_newest,
15426                        Some(Autoscroll::newest()),
15427                        window,
15428                        cx,
15429                    );
15430                }
15431                if selections.len() == 1 {
15432                    let selection = selections
15433                        .last()
15434                        .expect("ensured that there's only one selection");
15435                    let query = buffer
15436                        .text_for_range(selection.start..selection.end)
15437                        .collect::<String>();
15438                    let is_empty = query.is_empty();
15439                    let select_state = SelectNextState {
15440                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15441                        wordwise: true,
15442                        done: is_empty,
15443                    };
15444                    self.select_prev_state = Some(select_state);
15445                } else {
15446                    self.select_prev_state = None;
15447                }
15448            } else if let Some(selected_text) = selected_text {
15449                self.select_prev_state = Some(SelectNextState {
15450                    query: self
15451                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15452                    wordwise: false,
15453                    done: false,
15454                });
15455                self.select_previous(action, window, cx)?;
15456            }
15457        }
15458        Ok(())
15459    }
15460
15461    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15462    /// setting the case sensitivity based on the global
15463    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15464    /// editor's settings.
15465    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15466    where
15467        I: IntoIterator<Item = P>,
15468        P: AsRef<[u8]>,
15469    {
15470        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
15471            || EditorSettings::get_global(cx).search.case_sensitive,
15472            |value| value,
15473        );
15474
15475        let mut builder = AhoCorasickBuilder::new();
15476        builder.ascii_case_insensitive(!case_sensitive);
15477        builder.build(patterns)
15478    }
15479
15480    pub fn find_next_match(
15481        &mut self,
15482        _: &FindNextMatch,
15483        window: &mut Window,
15484        cx: &mut Context<Self>,
15485    ) -> Result<()> {
15486        let selections = self.selections.disjoint_anchors_arc();
15487        match selections.first() {
15488            Some(first) if selections.len() >= 2 => {
15489                self.change_selections(Default::default(), window, cx, |s| {
15490                    s.select_ranges([first.range()]);
15491                });
15492            }
15493            _ => self.select_next(
15494                &SelectNext {
15495                    replace_newest: true,
15496                },
15497                window,
15498                cx,
15499            )?,
15500        }
15501        Ok(())
15502    }
15503
15504    pub fn find_previous_match(
15505        &mut self,
15506        _: &FindPreviousMatch,
15507        window: &mut Window,
15508        cx: &mut Context<Self>,
15509    ) -> Result<()> {
15510        let selections = self.selections.disjoint_anchors_arc();
15511        match selections.last() {
15512            Some(last) if selections.len() >= 2 => {
15513                self.change_selections(Default::default(), window, cx, |s| {
15514                    s.select_ranges([last.range()]);
15515                });
15516            }
15517            _ => self.select_previous(
15518                &SelectPrevious {
15519                    replace_newest: true,
15520                },
15521                window,
15522                cx,
15523            )?,
15524        }
15525        Ok(())
15526    }
15527
15528    pub fn toggle_comments(
15529        &mut self,
15530        action: &ToggleComments,
15531        window: &mut Window,
15532        cx: &mut Context<Self>,
15533    ) {
15534        if self.read_only(cx) {
15535            return;
15536        }
15537        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15538        let text_layout_details = &self.text_layout_details(window);
15539        self.transact(window, cx, |this, window, cx| {
15540            let mut selections = this
15541                .selections
15542                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15543            let mut edits = Vec::new();
15544            let mut selection_edit_ranges = Vec::new();
15545            let mut last_toggled_row = None;
15546            let snapshot = this.buffer.read(cx).read(cx);
15547            let empty_str: Arc<str> = Arc::default();
15548            let mut suffixes_inserted = Vec::new();
15549            let ignore_indent = action.ignore_indent;
15550
15551            fn comment_prefix_range(
15552                snapshot: &MultiBufferSnapshot,
15553                row: MultiBufferRow,
15554                comment_prefix: &str,
15555                comment_prefix_whitespace: &str,
15556                ignore_indent: bool,
15557            ) -> Range<Point> {
15558                let indent_size = if ignore_indent {
15559                    0
15560                } else {
15561                    snapshot.indent_size_for_line(row).len
15562                };
15563
15564                let start = Point::new(row.0, indent_size);
15565
15566                let mut line_bytes = snapshot
15567                    .bytes_in_range(start..snapshot.max_point())
15568                    .flatten()
15569                    .copied();
15570
15571                // If this line currently begins with the line comment prefix, then record
15572                // the range containing the prefix.
15573                if line_bytes
15574                    .by_ref()
15575                    .take(comment_prefix.len())
15576                    .eq(comment_prefix.bytes())
15577                {
15578                    // Include any whitespace that matches the comment prefix.
15579                    let matching_whitespace_len = line_bytes
15580                        .zip(comment_prefix_whitespace.bytes())
15581                        .take_while(|(a, b)| a == b)
15582                        .count() as u32;
15583                    let end = Point::new(
15584                        start.row,
15585                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15586                    );
15587                    start..end
15588                } else {
15589                    start..start
15590                }
15591            }
15592
15593            fn comment_suffix_range(
15594                snapshot: &MultiBufferSnapshot,
15595                row: MultiBufferRow,
15596                comment_suffix: &str,
15597                comment_suffix_has_leading_space: bool,
15598            ) -> Range<Point> {
15599                let end = Point::new(row.0, snapshot.line_len(row));
15600                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15601
15602                let mut line_end_bytes = snapshot
15603                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15604                    .flatten()
15605                    .copied();
15606
15607                let leading_space_len = if suffix_start_column > 0
15608                    && line_end_bytes.next() == Some(b' ')
15609                    && comment_suffix_has_leading_space
15610                {
15611                    1
15612                } else {
15613                    0
15614                };
15615
15616                // If this line currently begins with the line comment prefix, then record
15617                // the range containing the prefix.
15618                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15619                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15620                    start..end
15621                } else {
15622                    end..end
15623                }
15624            }
15625
15626            // TODO: Handle selections that cross excerpts
15627            for selection in &mut selections {
15628                let start_column = snapshot
15629                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15630                    .len;
15631                let language = if let Some(language) =
15632                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15633                {
15634                    language
15635                } else {
15636                    continue;
15637                };
15638
15639                selection_edit_ranges.clear();
15640
15641                // If multiple selections contain a given row, avoid processing that
15642                // row more than once.
15643                let mut start_row = MultiBufferRow(selection.start.row);
15644                if last_toggled_row == Some(start_row) {
15645                    start_row = start_row.next_row();
15646                }
15647                let end_row =
15648                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15649                        MultiBufferRow(selection.end.row - 1)
15650                    } else {
15651                        MultiBufferRow(selection.end.row)
15652                    };
15653                last_toggled_row = Some(end_row);
15654
15655                if start_row > end_row {
15656                    continue;
15657                }
15658
15659                // If the language has line comments, toggle those.
15660                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15661
15662                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15663                if ignore_indent {
15664                    full_comment_prefixes = full_comment_prefixes
15665                        .into_iter()
15666                        .map(|s| Arc::from(s.trim_end()))
15667                        .collect();
15668                }
15669
15670                if !full_comment_prefixes.is_empty() {
15671                    let first_prefix = full_comment_prefixes
15672                        .first()
15673                        .expect("prefixes is non-empty");
15674                    let prefix_trimmed_lengths = full_comment_prefixes
15675                        .iter()
15676                        .map(|p| p.trim_end_matches(' ').len())
15677                        .collect::<SmallVec<[usize; 4]>>();
15678
15679                    let mut all_selection_lines_are_comments = true;
15680
15681                    for row in start_row.0..=end_row.0 {
15682                        let row = MultiBufferRow(row);
15683                        if start_row < end_row && snapshot.is_line_blank(row) {
15684                            continue;
15685                        }
15686
15687                        let prefix_range = full_comment_prefixes
15688                            .iter()
15689                            .zip(prefix_trimmed_lengths.iter().copied())
15690                            .map(|(prefix, trimmed_prefix_len)| {
15691                                comment_prefix_range(
15692                                    snapshot.deref(),
15693                                    row,
15694                                    &prefix[..trimmed_prefix_len],
15695                                    &prefix[trimmed_prefix_len..],
15696                                    ignore_indent,
15697                                )
15698                            })
15699                            .max_by_key(|range| range.end.column - range.start.column)
15700                            .expect("prefixes is non-empty");
15701
15702                        if prefix_range.is_empty() {
15703                            all_selection_lines_are_comments = false;
15704                        }
15705
15706                        selection_edit_ranges.push(prefix_range);
15707                    }
15708
15709                    if all_selection_lines_are_comments {
15710                        edits.extend(
15711                            selection_edit_ranges
15712                                .iter()
15713                                .cloned()
15714                                .map(|range| (range, empty_str.clone())),
15715                        );
15716                    } else {
15717                        let min_column = selection_edit_ranges
15718                            .iter()
15719                            .map(|range| range.start.column)
15720                            .min()
15721                            .unwrap_or(0);
15722                        edits.extend(selection_edit_ranges.iter().map(|range| {
15723                            let position = Point::new(range.start.row, min_column);
15724                            (position..position, first_prefix.clone())
15725                        }));
15726                    }
15727                } else if let Some(BlockCommentConfig {
15728                    start: full_comment_prefix,
15729                    end: comment_suffix,
15730                    ..
15731                }) = language.block_comment()
15732                {
15733                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15734                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15735                    let prefix_range = comment_prefix_range(
15736                        snapshot.deref(),
15737                        start_row,
15738                        comment_prefix,
15739                        comment_prefix_whitespace,
15740                        ignore_indent,
15741                    );
15742                    let suffix_range = comment_suffix_range(
15743                        snapshot.deref(),
15744                        end_row,
15745                        comment_suffix.trim_start_matches(' '),
15746                        comment_suffix.starts_with(' '),
15747                    );
15748
15749                    if prefix_range.is_empty() || suffix_range.is_empty() {
15750                        edits.push((
15751                            prefix_range.start..prefix_range.start,
15752                            full_comment_prefix.clone(),
15753                        ));
15754                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15755                        suffixes_inserted.push((end_row, comment_suffix.len()));
15756                    } else {
15757                        edits.push((prefix_range, empty_str.clone()));
15758                        edits.push((suffix_range, empty_str.clone()));
15759                    }
15760                } else {
15761                    continue;
15762                }
15763            }
15764
15765            drop(snapshot);
15766            this.buffer.update(cx, |buffer, cx| {
15767                buffer.edit(edits, None, cx);
15768            });
15769
15770            // Adjust selections so that they end before any comment suffixes that
15771            // were inserted.
15772            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15773            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15774            let snapshot = this.buffer.read(cx).read(cx);
15775            for selection in &mut selections {
15776                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15777                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15778                        Ordering::Less => {
15779                            suffixes_inserted.next();
15780                            continue;
15781                        }
15782                        Ordering::Greater => break,
15783                        Ordering::Equal => {
15784                            if selection.end.column == snapshot.line_len(row) {
15785                                if selection.is_empty() {
15786                                    selection.start.column -= suffix_len as u32;
15787                                }
15788                                selection.end.column -= suffix_len as u32;
15789                            }
15790                            break;
15791                        }
15792                    }
15793                }
15794            }
15795
15796            drop(snapshot);
15797            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15798
15799            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15800            let selections_on_single_row = selections.windows(2).all(|selections| {
15801                selections[0].start.row == selections[1].start.row
15802                    && selections[0].end.row == selections[1].end.row
15803                    && selections[0].start.row == selections[0].end.row
15804            });
15805            let selections_selecting = selections
15806                .iter()
15807                .any(|selection| selection.start != selection.end);
15808            let advance_downwards = action.advance_downwards
15809                && selections_on_single_row
15810                && !selections_selecting
15811                && !matches!(this.mode, EditorMode::SingleLine);
15812
15813            if advance_downwards {
15814                let snapshot = this.buffer.read(cx).snapshot(cx);
15815
15816                this.change_selections(Default::default(), window, cx, |s| {
15817                    s.move_cursors_with(|display_snapshot, display_point, _| {
15818                        let mut point = display_point.to_point(display_snapshot);
15819                        point.row += 1;
15820                        point = snapshot.clip_point(point, Bias::Left);
15821                        let display_point = point.to_display_point(display_snapshot);
15822                        let goal = SelectionGoal::HorizontalPosition(
15823                            display_snapshot
15824                                .x_for_display_point(display_point, text_layout_details)
15825                                .into(),
15826                        );
15827                        (display_point, goal)
15828                    })
15829                });
15830            }
15831        });
15832    }
15833
15834    pub fn select_enclosing_symbol(
15835        &mut self,
15836        _: &SelectEnclosingSymbol,
15837        window: &mut Window,
15838        cx: &mut Context<Self>,
15839    ) {
15840        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15841
15842        let buffer = self.buffer.read(cx).snapshot(cx);
15843        let old_selections = self
15844            .selections
15845            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15846            .into_boxed_slice();
15847
15848        fn update_selection(
15849            selection: &Selection<MultiBufferOffset>,
15850            buffer_snap: &MultiBufferSnapshot,
15851        ) -> Option<Selection<MultiBufferOffset>> {
15852            let cursor = selection.head();
15853            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15854            for symbol in symbols.iter().rev() {
15855                let start = symbol.range.start.to_offset(buffer_snap);
15856                let end = symbol.range.end.to_offset(buffer_snap);
15857                let new_range = start..end;
15858                if start < selection.start || end > selection.end {
15859                    return Some(Selection {
15860                        id: selection.id,
15861                        start: new_range.start,
15862                        end: new_range.end,
15863                        goal: SelectionGoal::None,
15864                        reversed: selection.reversed,
15865                    });
15866                }
15867            }
15868            None
15869        }
15870
15871        let mut selected_larger_symbol = false;
15872        let new_selections = old_selections
15873            .iter()
15874            .map(|selection| match update_selection(selection, &buffer) {
15875                Some(new_selection) => {
15876                    if new_selection.range() != selection.range() {
15877                        selected_larger_symbol = true;
15878                    }
15879                    new_selection
15880                }
15881                None => selection.clone(),
15882            })
15883            .collect::<Vec<_>>();
15884
15885        if selected_larger_symbol {
15886            self.change_selections(Default::default(), window, cx, |s| {
15887                s.select(new_selections);
15888            });
15889        }
15890    }
15891
15892    pub fn select_larger_syntax_node(
15893        &mut self,
15894        _: &SelectLargerSyntaxNode,
15895        window: &mut Window,
15896        cx: &mut Context<Self>,
15897    ) {
15898        let Some(visible_row_count) = self.visible_row_count() else {
15899            return;
15900        };
15901        let old_selections: Box<[_]> = self
15902            .selections
15903            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15904            .into();
15905        if old_selections.is_empty() {
15906            return;
15907        }
15908
15909        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15910
15911        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15912        let buffer = self.buffer.read(cx).snapshot(cx);
15913
15914        let mut selected_larger_node = false;
15915        let mut new_selections = old_selections
15916            .iter()
15917            .map(|selection| {
15918                let old_range = selection.start..selection.end;
15919
15920                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15921                    // manually select word at selection
15922                    if ["string_content", "inline"].contains(&node.kind()) {
15923                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15924                        // ignore if word is already selected
15925                        if !word_range.is_empty() && old_range != word_range {
15926                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15927                            // only select word if start and end point belongs to same word
15928                            if word_range == last_word_range {
15929                                selected_larger_node = true;
15930                                return Selection {
15931                                    id: selection.id,
15932                                    start: word_range.start,
15933                                    end: word_range.end,
15934                                    goal: SelectionGoal::None,
15935                                    reversed: selection.reversed,
15936                                };
15937                            }
15938                        }
15939                    }
15940                }
15941
15942                let mut new_range = old_range.clone();
15943                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15944                    new_range = range;
15945                    if !node.is_named() {
15946                        continue;
15947                    }
15948                    if !display_map.intersects_fold(new_range.start)
15949                        && !display_map.intersects_fold(new_range.end)
15950                    {
15951                        break;
15952                    }
15953                }
15954
15955                selected_larger_node |= new_range != old_range;
15956                Selection {
15957                    id: selection.id,
15958                    start: new_range.start,
15959                    end: new_range.end,
15960                    goal: SelectionGoal::None,
15961                    reversed: selection.reversed,
15962                }
15963            })
15964            .collect::<Vec<_>>();
15965
15966        if !selected_larger_node {
15967            return; // don't put this call in the history
15968        }
15969
15970        // scroll based on transformation done to the last selection created by the user
15971        let (last_old, last_new) = old_selections
15972            .last()
15973            .zip(new_selections.last().cloned())
15974            .expect("old_selections isn't empty");
15975
15976        // revert selection
15977        let is_selection_reversed = {
15978            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15979            new_selections.last_mut().expect("checked above").reversed =
15980                should_newest_selection_be_reversed;
15981            should_newest_selection_be_reversed
15982        };
15983
15984        if selected_larger_node {
15985            self.select_syntax_node_history.disable_clearing = true;
15986            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15987                s.select(new_selections.clone());
15988            });
15989            self.select_syntax_node_history.disable_clearing = false;
15990        }
15991
15992        let start_row = last_new.start.to_display_point(&display_map).row().0;
15993        let end_row = last_new.end.to_display_point(&display_map).row().0;
15994        let selection_height = end_row - start_row + 1;
15995        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15996
15997        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15998        let scroll_behavior = if fits_on_the_screen {
15999            self.request_autoscroll(Autoscroll::fit(), cx);
16000            SelectSyntaxNodeScrollBehavior::FitSelection
16001        } else if is_selection_reversed {
16002            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16003            SelectSyntaxNodeScrollBehavior::CursorTop
16004        } else {
16005            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16006            SelectSyntaxNodeScrollBehavior::CursorBottom
16007        };
16008
16009        self.select_syntax_node_history.push((
16010            old_selections,
16011            scroll_behavior,
16012            is_selection_reversed,
16013        ));
16014    }
16015
16016    pub fn select_smaller_syntax_node(
16017        &mut self,
16018        _: &SelectSmallerSyntaxNode,
16019        window: &mut Window,
16020        cx: &mut Context<Self>,
16021    ) {
16022        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16023
16024        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16025            self.select_syntax_node_history.pop()
16026        {
16027            if let Some(selection) = selections.last_mut() {
16028                selection.reversed = is_selection_reversed;
16029            }
16030
16031            self.select_syntax_node_history.disable_clearing = true;
16032            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16033                s.select(selections.to_vec());
16034            });
16035            self.select_syntax_node_history.disable_clearing = false;
16036
16037            match scroll_behavior {
16038                SelectSyntaxNodeScrollBehavior::CursorTop => {
16039                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16040                }
16041                SelectSyntaxNodeScrollBehavior::FitSelection => {
16042                    self.request_autoscroll(Autoscroll::fit(), cx);
16043                }
16044                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16045                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16046                }
16047            }
16048        }
16049    }
16050
16051    pub fn unwrap_syntax_node(
16052        &mut self,
16053        _: &UnwrapSyntaxNode,
16054        window: &mut Window,
16055        cx: &mut Context<Self>,
16056    ) {
16057        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16058
16059        let buffer = self.buffer.read(cx).snapshot(cx);
16060        let selections = self
16061            .selections
16062            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16063            .into_iter()
16064            // subtracting the offset requires sorting
16065            .sorted_by_key(|i| i.start);
16066
16067        let full_edits = selections
16068            .into_iter()
16069            .filter_map(|selection| {
16070                let child = if selection.is_empty()
16071                    && let Some((_, ancestor_range)) =
16072                        buffer.syntax_ancestor(selection.start..selection.end)
16073                {
16074                    ancestor_range
16075                } else {
16076                    selection.range()
16077                };
16078
16079                let mut parent = child.clone();
16080                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16081                    parent = ancestor_range;
16082                    if parent.start < child.start || parent.end > child.end {
16083                        break;
16084                    }
16085                }
16086
16087                if parent == child {
16088                    return None;
16089                }
16090                let text = buffer.text_for_range(child).collect::<String>();
16091                Some((selection.id, parent, text))
16092            })
16093            .collect::<Vec<_>>();
16094        if full_edits.is_empty() {
16095            return;
16096        }
16097
16098        self.transact(window, cx, |this, window, cx| {
16099            this.buffer.update(cx, |buffer, cx| {
16100                buffer.edit(
16101                    full_edits
16102                        .iter()
16103                        .map(|(_, p, t)| (p.clone(), t.clone()))
16104                        .collect::<Vec<_>>(),
16105                    None,
16106                    cx,
16107                );
16108            });
16109            this.change_selections(Default::default(), window, cx, |s| {
16110                let mut offset = 0;
16111                let mut selections = vec![];
16112                for (id, parent, text) in full_edits {
16113                    let start = parent.start - offset;
16114                    offset += (parent.end - parent.start) - text.len();
16115                    selections.push(Selection {
16116                        id,
16117                        start,
16118                        end: start + text.len(),
16119                        reversed: false,
16120                        goal: Default::default(),
16121                    });
16122                }
16123                s.select(selections);
16124            });
16125        });
16126    }
16127
16128    pub fn select_next_syntax_node(
16129        &mut self,
16130        _: &SelectNextSyntaxNode,
16131        window: &mut Window,
16132        cx: &mut Context<Self>,
16133    ) {
16134        let old_selections: Box<[_]> = self
16135            .selections
16136            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16137            .into();
16138        if old_selections.is_empty() {
16139            return;
16140        }
16141
16142        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16143
16144        let buffer = self.buffer.read(cx).snapshot(cx);
16145        let mut selected_sibling = false;
16146
16147        let new_selections = old_selections
16148            .iter()
16149            .map(|selection| {
16150                let old_range = selection.start..selection.end;
16151
16152                let old_range =
16153                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16154                let excerpt = buffer.excerpt_containing(old_range.clone());
16155
16156                if let Some(mut excerpt) = excerpt
16157                    && let Some(node) = excerpt
16158                        .buffer()
16159                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16160                {
16161                    let new_range = excerpt.map_range_from_buffer(
16162                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16163                    );
16164                    selected_sibling = true;
16165                    Selection {
16166                        id: selection.id,
16167                        start: new_range.start,
16168                        end: new_range.end,
16169                        goal: SelectionGoal::None,
16170                        reversed: selection.reversed,
16171                    }
16172                } else {
16173                    selection.clone()
16174                }
16175            })
16176            .collect::<Vec<_>>();
16177
16178        if selected_sibling {
16179            self.change_selections(
16180                SelectionEffects::scroll(Autoscroll::fit()),
16181                window,
16182                cx,
16183                |s| {
16184                    s.select(new_selections);
16185                },
16186            );
16187        }
16188    }
16189
16190    pub fn select_prev_syntax_node(
16191        &mut self,
16192        _: &SelectPreviousSyntaxNode,
16193        window: &mut Window,
16194        cx: &mut Context<Self>,
16195    ) {
16196        let old_selections: Box<[_]> = self
16197            .selections
16198            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16199            .into();
16200        if old_selections.is_empty() {
16201            return;
16202        }
16203
16204        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16205
16206        let buffer = self.buffer.read(cx).snapshot(cx);
16207        let mut selected_sibling = false;
16208
16209        let new_selections = old_selections
16210            .iter()
16211            .map(|selection| {
16212                let old_range = selection.start..selection.end;
16213                let old_range =
16214                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16215                let excerpt = buffer.excerpt_containing(old_range.clone());
16216
16217                if let Some(mut excerpt) = excerpt
16218                    && let Some(node) = excerpt
16219                        .buffer()
16220                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16221                {
16222                    let new_range = excerpt.map_range_from_buffer(
16223                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16224                    );
16225                    selected_sibling = true;
16226                    Selection {
16227                        id: selection.id,
16228                        start: new_range.start,
16229                        end: new_range.end,
16230                        goal: SelectionGoal::None,
16231                        reversed: selection.reversed,
16232                    }
16233                } else {
16234                    selection.clone()
16235                }
16236            })
16237            .collect::<Vec<_>>();
16238
16239        if selected_sibling {
16240            self.change_selections(
16241                SelectionEffects::scroll(Autoscroll::fit()),
16242                window,
16243                cx,
16244                |s| {
16245                    s.select(new_selections);
16246                },
16247            );
16248        }
16249    }
16250
16251    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16252        if !EditorSettings::get_global(cx).gutter.runnables {
16253            self.clear_tasks();
16254            return Task::ready(());
16255        }
16256        let project = self.project().map(Entity::downgrade);
16257        let task_sources = self.lsp_task_sources(cx);
16258        let multi_buffer = self.buffer.downgrade();
16259        cx.spawn_in(window, async move |editor, cx| {
16260            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16261            let Some(project) = project.and_then(|p| p.upgrade()) else {
16262                return;
16263            };
16264            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16265                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16266            }) else {
16267                return;
16268            };
16269
16270            let hide_runnables = project
16271                .update(cx, |project, _| project.is_via_collab())
16272                .unwrap_or(true);
16273            if hide_runnables {
16274                return;
16275            }
16276            let new_rows =
16277                cx.background_spawn({
16278                    let snapshot = display_snapshot.clone();
16279                    async move {
16280                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16281                    }
16282                })
16283                    .await;
16284            let Ok(lsp_tasks) =
16285                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16286            else {
16287                return;
16288            };
16289            let lsp_tasks = lsp_tasks.await;
16290
16291            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16292                lsp_tasks
16293                    .into_iter()
16294                    .flat_map(|(kind, tasks)| {
16295                        tasks.into_iter().filter_map(move |(location, task)| {
16296                            Some((kind.clone(), location?, task))
16297                        })
16298                    })
16299                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16300                        let buffer = location.target.buffer;
16301                        let buffer_snapshot = buffer.read(cx).snapshot();
16302                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16303                            |(excerpt_id, snapshot, _)| {
16304                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16305                                    display_snapshot
16306                                        .buffer_snapshot()
16307                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16308                                } else {
16309                                    None
16310                                }
16311                            },
16312                        );
16313                        if let Some(offset) = offset {
16314                            let task_buffer_range =
16315                                location.target.range.to_point(&buffer_snapshot);
16316                            let context_buffer_range =
16317                                task_buffer_range.to_offset(&buffer_snapshot);
16318                            let context_range = BufferOffset(context_buffer_range.start)
16319                                ..BufferOffset(context_buffer_range.end);
16320
16321                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16322                                .or_insert_with(|| RunnableTasks {
16323                                    templates: Vec::new(),
16324                                    offset,
16325                                    column: task_buffer_range.start.column,
16326                                    extra_variables: HashMap::default(),
16327                                    context_range,
16328                                })
16329                                .templates
16330                                .push((kind, task.original_task().clone()));
16331                        }
16332
16333                        acc
16334                    })
16335            }) else {
16336                return;
16337            };
16338
16339            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16340                buffer.language_settings(cx).tasks.prefer_lsp
16341            }) else {
16342                return;
16343            };
16344
16345            let rows = Self::runnable_rows(
16346                project,
16347                display_snapshot,
16348                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16349                new_rows,
16350                cx.clone(),
16351            )
16352            .await;
16353            editor
16354                .update(cx, |editor, _| {
16355                    editor.clear_tasks();
16356                    for (key, mut value) in rows {
16357                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16358                            value.templates.extend(lsp_tasks.templates);
16359                        }
16360
16361                        editor.insert_tasks(key, value);
16362                    }
16363                    for (key, value) in lsp_tasks_by_rows {
16364                        editor.insert_tasks(key, value);
16365                    }
16366                })
16367                .ok();
16368        })
16369    }
16370    fn fetch_runnable_ranges(
16371        snapshot: &DisplaySnapshot,
16372        range: Range<Anchor>,
16373    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16374        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16375    }
16376
16377    fn runnable_rows(
16378        project: Entity<Project>,
16379        snapshot: DisplaySnapshot,
16380        prefer_lsp: bool,
16381        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16382        cx: AsyncWindowContext,
16383    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16384        cx.spawn(async move |cx| {
16385            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16386            for (run_range, mut runnable) in runnable_ranges {
16387                let Some(tasks) = cx
16388                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16389                    .ok()
16390                else {
16391                    continue;
16392                };
16393                let mut tasks = tasks.await;
16394
16395                if prefer_lsp {
16396                    tasks.retain(|(task_kind, _)| {
16397                        !matches!(task_kind, TaskSourceKind::Language { .. })
16398                    });
16399                }
16400                if tasks.is_empty() {
16401                    continue;
16402                }
16403
16404                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16405                let Some(row) = snapshot
16406                    .buffer_snapshot()
16407                    .buffer_line_for_row(MultiBufferRow(point.row))
16408                    .map(|(_, range)| range.start.row)
16409                else {
16410                    continue;
16411                };
16412
16413                let context_range =
16414                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16415                runnable_rows.push((
16416                    (runnable.buffer_id, row),
16417                    RunnableTasks {
16418                        templates: tasks,
16419                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16420                        context_range,
16421                        column: point.column,
16422                        extra_variables: runnable.extra_captures,
16423                    },
16424                ));
16425            }
16426            runnable_rows
16427        })
16428    }
16429
16430    fn templates_with_tags(
16431        project: &Entity<Project>,
16432        runnable: &mut Runnable,
16433        cx: &mut App,
16434    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16435        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16436            let (worktree_id, file) = project
16437                .buffer_for_id(runnable.buffer, cx)
16438                .and_then(|buffer| buffer.read(cx).file())
16439                .map(|file| (file.worktree_id(cx), file.clone()))
16440                .unzip();
16441
16442            (
16443                project.task_store().read(cx).task_inventory().cloned(),
16444                worktree_id,
16445                file,
16446            )
16447        });
16448
16449        let tags = mem::take(&mut runnable.tags);
16450        let language = runnable.language.clone();
16451        cx.spawn(async move |cx| {
16452            let mut templates_with_tags = Vec::new();
16453            if let Some(inventory) = inventory {
16454                for RunnableTag(tag) in tags {
16455                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16456                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16457                    }) else {
16458                        return templates_with_tags;
16459                    };
16460                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16461                        move |(_, template)| {
16462                            template.tags.iter().any(|source_tag| source_tag == &tag)
16463                        },
16464                    ));
16465                }
16466            }
16467            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16468
16469            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16470                // Strongest source wins; if we have worktree tag binding, prefer that to
16471                // global and language bindings;
16472                // if we have a global binding, prefer that to language binding.
16473                let first_mismatch = templates_with_tags
16474                    .iter()
16475                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16476                if let Some(index) = first_mismatch {
16477                    templates_with_tags.truncate(index);
16478                }
16479            }
16480
16481            templates_with_tags
16482        })
16483    }
16484
16485    pub fn move_to_enclosing_bracket(
16486        &mut self,
16487        _: &MoveToEnclosingBracket,
16488        window: &mut Window,
16489        cx: &mut Context<Self>,
16490    ) {
16491        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16492        self.change_selections(Default::default(), window, cx, |s| {
16493            s.move_offsets_with(|snapshot, selection| {
16494                let Some(enclosing_bracket_ranges) =
16495                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16496                else {
16497                    return;
16498                };
16499
16500                let mut best_length = usize::MAX;
16501                let mut best_inside = false;
16502                let mut best_in_bracket_range = false;
16503                let mut best_destination = None;
16504                for (open, close) in enclosing_bracket_ranges {
16505                    let close = close.to_inclusive();
16506                    let length = *close.end() - open.start;
16507                    let inside = selection.start >= open.end && selection.end <= *close.start();
16508                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16509                        || close.contains(&selection.head());
16510
16511                    // If best is next to a bracket and current isn't, skip
16512                    if !in_bracket_range && best_in_bracket_range {
16513                        continue;
16514                    }
16515
16516                    // Prefer smaller lengths unless best is inside and current isn't
16517                    if length > best_length && (best_inside || !inside) {
16518                        continue;
16519                    }
16520
16521                    best_length = length;
16522                    best_inside = inside;
16523                    best_in_bracket_range = in_bracket_range;
16524                    best_destination = Some(
16525                        if close.contains(&selection.start) && close.contains(&selection.end) {
16526                            if inside { open.end } else { open.start }
16527                        } else if inside {
16528                            *close.start()
16529                        } else {
16530                            *close.end()
16531                        },
16532                    );
16533                }
16534
16535                if let Some(destination) = best_destination {
16536                    selection.collapse_to(destination, SelectionGoal::None);
16537                }
16538            })
16539        });
16540    }
16541
16542    pub fn undo_selection(
16543        &mut self,
16544        _: &UndoSelection,
16545        window: &mut Window,
16546        cx: &mut Context<Self>,
16547    ) {
16548        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16549        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16550            self.selection_history.mode = SelectionHistoryMode::Undoing;
16551            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16552                this.end_selection(window, cx);
16553                this.change_selections(
16554                    SelectionEffects::scroll(Autoscroll::newest()),
16555                    window,
16556                    cx,
16557                    |s| s.select_anchors(entry.selections.to_vec()),
16558                );
16559            });
16560            self.selection_history.mode = SelectionHistoryMode::Normal;
16561
16562            self.select_next_state = entry.select_next_state;
16563            self.select_prev_state = entry.select_prev_state;
16564            self.add_selections_state = entry.add_selections_state;
16565        }
16566    }
16567
16568    pub fn redo_selection(
16569        &mut self,
16570        _: &RedoSelection,
16571        window: &mut Window,
16572        cx: &mut Context<Self>,
16573    ) {
16574        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16575        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16576            self.selection_history.mode = SelectionHistoryMode::Redoing;
16577            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16578                this.end_selection(window, cx);
16579                this.change_selections(
16580                    SelectionEffects::scroll(Autoscroll::newest()),
16581                    window,
16582                    cx,
16583                    |s| s.select_anchors(entry.selections.to_vec()),
16584                );
16585            });
16586            self.selection_history.mode = SelectionHistoryMode::Normal;
16587
16588            self.select_next_state = entry.select_next_state;
16589            self.select_prev_state = entry.select_prev_state;
16590            self.add_selections_state = entry.add_selections_state;
16591        }
16592    }
16593
16594    pub fn expand_excerpts(
16595        &mut self,
16596        action: &ExpandExcerpts,
16597        _: &mut Window,
16598        cx: &mut Context<Self>,
16599    ) {
16600        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16601    }
16602
16603    pub fn expand_excerpts_down(
16604        &mut self,
16605        action: &ExpandExcerptsDown,
16606        _: &mut Window,
16607        cx: &mut Context<Self>,
16608    ) {
16609        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16610    }
16611
16612    pub fn expand_excerpts_up(
16613        &mut self,
16614        action: &ExpandExcerptsUp,
16615        _: &mut Window,
16616        cx: &mut Context<Self>,
16617    ) {
16618        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16619    }
16620
16621    pub fn expand_excerpts_for_direction(
16622        &mut self,
16623        lines: u32,
16624        direction: ExpandExcerptDirection,
16625
16626        cx: &mut Context<Self>,
16627    ) {
16628        let selections = self.selections.disjoint_anchors_arc();
16629
16630        let lines = if lines == 0 {
16631            EditorSettings::get_global(cx).expand_excerpt_lines
16632        } else {
16633            lines
16634        };
16635
16636        self.buffer.update(cx, |buffer, cx| {
16637            let snapshot = buffer.snapshot(cx);
16638            let mut excerpt_ids = selections
16639                .iter()
16640                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16641                .collect::<Vec<_>>();
16642            excerpt_ids.sort();
16643            excerpt_ids.dedup();
16644            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16645        })
16646    }
16647
16648    pub fn expand_excerpt(
16649        &mut self,
16650        excerpt: ExcerptId,
16651        direction: ExpandExcerptDirection,
16652        window: &mut Window,
16653        cx: &mut Context<Self>,
16654    ) {
16655        let current_scroll_position = self.scroll_position(cx);
16656        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16657        let mut scroll = None;
16658
16659        if direction == ExpandExcerptDirection::Down {
16660            let multi_buffer = self.buffer.read(cx);
16661            let snapshot = multi_buffer.snapshot(cx);
16662            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16663                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16664                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16665            {
16666                let buffer_snapshot = buffer.read(cx).snapshot();
16667                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16668                let last_row = buffer_snapshot.max_point().row;
16669                let lines_below = last_row.saturating_sub(excerpt_end_row);
16670                if lines_below >= lines_to_expand {
16671                    scroll = Some(
16672                        current_scroll_position
16673                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16674                    );
16675                }
16676            }
16677        }
16678        if direction == ExpandExcerptDirection::Up
16679            && self
16680                .buffer
16681                .read(cx)
16682                .snapshot(cx)
16683                .excerpt_before(excerpt)
16684                .is_none()
16685        {
16686            scroll = Some(current_scroll_position);
16687        }
16688
16689        self.buffer.update(cx, |buffer, cx| {
16690            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16691        });
16692
16693        if let Some(new_scroll_position) = scroll {
16694            self.set_scroll_position(new_scroll_position, window, cx);
16695        }
16696    }
16697
16698    pub fn go_to_singleton_buffer_point(
16699        &mut self,
16700        point: Point,
16701        window: &mut Window,
16702        cx: &mut Context<Self>,
16703    ) {
16704        self.go_to_singleton_buffer_range(point..point, window, cx);
16705    }
16706
16707    pub fn go_to_singleton_buffer_range(
16708        &mut self,
16709        range: Range<Point>,
16710        window: &mut Window,
16711        cx: &mut Context<Self>,
16712    ) {
16713        let multibuffer = self.buffer().read(cx);
16714        let Some(buffer) = multibuffer.as_singleton() else {
16715            return;
16716        };
16717        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16718            return;
16719        };
16720        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16721            return;
16722        };
16723        self.change_selections(
16724            SelectionEffects::default().nav_history(true),
16725            window,
16726            cx,
16727            |s| s.select_anchor_ranges([start..end]),
16728        );
16729    }
16730
16731    pub fn go_to_diagnostic(
16732        &mut self,
16733        action: &GoToDiagnostic,
16734        window: &mut Window,
16735        cx: &mut Context<Self>,
16736    ) {
16737        if !self.diagnostics_enabled() {
16738            return;
16739        }
16740        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16741        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16742    }
16743
16744    pub fn go_to_prev_diagnostic(
16745        &mut self,
16746        action: &GoToPreviousDiagnostic,
16747        window: &mut Window,
16748        cx: &mut Context<Self>,
16749    ) {
16750        if !self.diagnostics_enabled() {
16751            return;
16752        }
16753        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16754        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16755    }
16756
16757    pub fn go_to_diagnostic_impl(
16758        &mut self,
16759        direction: Direction,
16760        severity: GoToDiagnosticSeverityFilter,
16761        window: &mut Window,
16762        cx: &mut Context<Self>,
16763    ) {
16764        let buffer = self.buffer.read(cx).snapshot(cx);
16765        let selection = self
16766            .selections
16767            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16768
16769        let mut active_group_id = None;
16770        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16771            && active_group.active_range.start.to_offset(&buffer) == selection.start
16772        {
16773            active_group_id = Some(active_group.group_id);
16774        }
16775
16776        fn filtered<'a>(
16777            severity: GoToDiagnosticSeverityFilter,
16778            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16779        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16780            diagnostics
16781                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16782                .filter(|entry| entry.range.start != entry.range.end)
16783                .filter(|entry| !entry.diagnostic.is_unnecessary)
16784        }
16785
16786        let before = filtered(
16787            severity,
16788            buffer
16789                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16790                .filter(|entry| entry.range.start <= selection.start),
16791        );
16792        let after = filtered(
16793            severity,
16794            buffer
16795                .diagnostics_in_range(selection.start..buffer.len())
16796                .filter(|entry| entry.range.start >= selection.start),
16797        );
16798
16799        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16800        if direction == Direction::Prev {
16801            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16802            {
16803                for diagnostic in prev_diagnostics.into_iter().rev() {
16804                    if diagnostic.range.start != selection.start
16805                        || active_group_id
16806                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16807                    {
16808                        found = Some(diagnostic);
16809                        break 'outer;
16810                    }
16811                }
16812            }
16813        } else {
16814            for diagnostic in after.chain(before) {
16815                if diagnostic.range.start != selection.start
16816                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16817                {
16818                    found = Some(diagnostic);
16819                    break;
16820                }
16821            }
16822        }
16823        let Some(next_diagnostic) = found else {
16824            return;
16825        };
16826
16827        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16828        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16829            return;
16830        };
16831        let snapshot = self.snapshot(window, cx);
16832        if snapshot.intersects_fold(next_diagnostic.range.start) {
16833            self.unfold_ranges(
16834                std::slice::from_ref(&next_diagnostic.range),
16835                true,
16836                false,
16837                cx,
16838            );
16839        }
16840        self.change_selections(Default::default(), window, cx, |s| {
16841            s.select_ranges(vec![
16842                next_diagnostic.range.start..next_diagnostic.range.start,
16843            ])
16844        });
16845        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16846        self.refresh_edit_prediction(false, true, window, cx);
16847    }
16848
16849    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16850        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16851        let snapshot = self.snapshot(window, cx);
16852        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16853        self.go_to_hunk_before_or_after_position(
16854            &snapshot,
16855            selection.head(),
16856            Direction::Next,
16857            window,
16858            cx,
16859        );
16860    }
16861
16862    pub fn go_to_hunk_before_or_after_position(
16863        &mut self,
16864        snapshot: &EditorSnapshot,
16865        position: Point,
16866        direction: Direction,
16867        window: &mut Window,
16868        cx: &mut Context<Editor>,
16869    ) {
16870        let row = if direction == Direction::Next {
16871            self.hunk_after_position(snapshot, position)
16872                .map(|hunk| hunk.row_range.start)
16873        } else {
16874            self.hunk_before_position(snapshot, position)
16875        };
16876
16877        if let Some(row) = row {
16878            let destination = Point::new(row.0, 0);
16879            let autoscroll = Autoscroll::center();
16880
16881            self.unfold_ranges(&[destination..destination], false, false, cx);
16882            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16883                s.select_ranges([destination..destination]);
16884            });
16885        }
16886    }
16887
16888    fn hunk_after_position(
16889        &mut self,
16890        snapshot: &EditorSnapshot,
16891        position: Point,
16892    ) -> Option<MultiBufferDiffHunk> {
16893        snapshot
16894            .buffer_snapshot()
16895            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16896            .find(|hunk| hunk.row_range.start.0 > position.row)
16897            .or_else(|| {
16898                snapshot
16899                    .buffer_snapshot()
16900                    .diff_hunks_in_range(Point::zero()..position)
16901                    .find(|hunk| hunk.row_range.end.0 < position.row)
16902            })
16903    }
16904
16905    fn go_to_prev_hunk(
16906        &mut self,
16907        _: &GoToPreviousHunk,
16908        window: &mut Window,
16909        cx: &mut Context<Self>,
16910    ) {
16911        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16912        let snapshot = self.snapshot(window, cx);
16913        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16914        self.go_to_hunk_before_or_after_position(
16915            &snapshot,
16916            selection.head(),
16917            Direction::Prev,
16918            window,
16919            cx,
16920        );
16921    }
16922
16923    fn hunk_before_position(
16924        &mut self,
16925        snapshot: &EditorSnapshot,
16926        position: Point,
16927    ) -> Option<MultiBufferRow> {
16928        snapshot
16929            .buffer_snapshot()
16930            .diff_hunk_before(position)
16931            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16932    }
16933
16934    fn go_to_next_change(
16935        &mut self,
16936        _: &GoToNextChange,
16937        window: &mut Window,
16938        cx: &mut Context<Self>,
16939    ) {
16940        if let Some(selections) = self
16941            .change_list
16942            .next_change(1, Direction::Next)
16943            .map(|s| s.to_vec())
16944        {
16945            self.change_selections(Default::default(), window, cx, |s| {
16946                let map = s.display_snapshot();
16947                s.select_display_ranges(selections.iter().map(|a| {
16948                    let point = a.to_display_point(&map);
16949                    point..point
16950                }))
16951            })
16952        }
16953    }
16954
16955    fn go_to_previous_change(
16956        &mut self,
16957        _: &GoToPreviousChange,
16958        window: &mut Window,
16959        cx: &mut Context<Self>,
16960    ) {
16961        if let Some(selections) = self
16962            .change_list
16963            .next_change(1, Direction::Prev)
16964            .map(|s| s.to_vec())
16965        {
16966            self.change_selections(Default::default(), window, cx, |s| {
16967                let map = s.display_snapshot();
16968                s.select_display_ranges(selections.iter().map(|a| {
16969                    let point = a.to_display_point(&map);
16970                    point..point
16971                }))
16972            })
16973        }
16974    }
16975
16976    pub fn go_to_next_document_highlight(
16977        &mut self,
16978        _: &GoToNextDocumentHighlight,
16979        window: &mut Window,
16980        cx: &mut Context<Self>,
16981    ) {
16982        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16983    }
16984
16985    pub fn go_to_prev_document_highlight(
16986        &mut self,
16987        _: &GoToPreviousDocumentHighlight,
16988        window: &mut Window,
16989        cx: &mut Context<Self>,
16990    ) {
16991        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16992    }
16993
16994    pub fn go_to_document_highlight_before_or_after_position(
16995        &mut self,
16996        direction: Direction,
16997        window: &mut Window,
16998        cx: &mut Context<Editor>,
16999    ) {
17000        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17001        let snapshot = self.snapshot(window, cx);
17002        let buffer = &snapshot.buffer_snapshot();
17003        let position = self
17004            .selections
17005            .newest::<Point>(&snapshot.display_snapshot)
17006            .head();
17007        let anchor_position = buffer.anchor_after(position);
17008
17009        // Get all document highlights (both read and write)
17010        let mut all_highlights = Vec::new();
17011
17012        if let Some((_, read_highlights)) = self
17013            .background_highlights
17014            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
17015        {
17016            all_highlights.extend(read_highlights.iter());
17017        }
17018
17019        if let Some((_, write_highlights)) = self
17020            .background_highlights
17021            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
17022        {
17023            all_highlights.extend(write_highlights.iter());
17024        }
17025
17026        if all_highlights.is_empty() {
17027            return;
17028        }
17029
17030        // Sort highlights by position
17031        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17032
17033        let target_highlight = match direction {
17034            Direction::Next => {
17035                // Find the first highlight after the current position
17036                all_highlights
17037                    .iter()
17038                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17039            }
17040            Direction::Prev => {
17041                // Find the last highlight before the current position
17042                all_highlights
17043                    .iter()
17044                    .rev()
17045                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17046            }
17047        };
17048
17049        if let Some(highlight) = target_highlight {
17050            let destination = highlight.start.to_point(buffer);
17051            let autoscroll = Autoscroll::center();
17052
17053            self.unfold_ranges(&[destination..destination], false, false, cx);
17054            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17055                s.select_ranges([destination..destination]);
17056            });
17057        }
17058    }
17059
17060    fn go_to_line<T: 'static>(
17061        &mut self,
17062        position: Anchor,
17063        highlight_color: Option<Hsla>,
17064        window: &mut Window,
17065        cx: &mut Context<Self>,
17066    ) {
17067        let snapshot = self.snapshot(window, cx).display_snapshot;
17068        let position = position.to_point(&snapshot.buffer_snapshot());
17069        let start = snapshot
17070            .buffer_snapshot()
17071            .clip_point(Point::new(position.row, 0), Bias::Left);
17072        let end = start + Point::new(1, 0);
17073        let start = snapshot.buffer_snapshot().anchor_before(start);
17074        let end = snapshot.buffer_snapshot().anchor_before(end);
17075
17076        self.highlight_rows::<T>(
17077            start..end,
17078            highlight_color
17079                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17080            Default::default(),
17081            cx,
17082        );
17083
17084        if self.buffer.read(cx).is_singleton() {
17085            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17086        }
17087    }
17088
17089    pub fn go_to_definition(
17090        &mut self,
17091        _: &GoToDefinition,
17092        window: &mut Window,
17093        cx: &mut Context<Self>,
17094    ) -> Task<Result<Navigated>> {
17095        let definition =
17096            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17097        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17098        cx.spawn_in(window, async move |editor, cx| {
17099            if definition.await? == Navigated::Yes {
17100                return Ok(Navigated::Yes);
17101            }
17102            match fallback_strategy {
17103                GoToDefinitionFallback::None => Ok(Navigated::No),
17104                GoToDefinitionFallback::FindAllReferences => {
17105                    match editor.update_in(cx, |editor, window, cx| {
17106                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17107                    })? {
17108                        Some(references) => references.await,
17109                        None => Ok(Navigated::No),
17110                    }
17111                }
17112            }
17113        })
17114    }
17115
17116    pub fn go_to_declaration(
17117        &mut self,
17118        _: &GoToDeclaration,
17119        window: &mut Window,
17120        cx: &mut Context<Self>,
17121    ) -> Task<Result<Navigated>> {
17122        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17123    }
17124
17125    pub fn go_to_declaration_split(
17126        &mut self,
17127        _: &GoToDeclaration,
17128        window: &mut Window,
17129        cx: &mut Context<Self>,
17130    ) -> Task<Result<Navigated>> {
17131        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17132    }
17133
17134    pub fn go_to_implementation(
17135        &mut self,
17136        _: &GoToImplementation,
17137        window: &mut Window,
17138        cx: &mut Context<Self>,
17139    ) -> Task<Result<Navigated>> {
17140        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17141    }
17142
17143    pub fn go_to_implementation_split(
17144        &mut self,
17145        _: &GoToImplementationSplit,
17146        window: &mut Window,
17147        cx: &mut Context<Self>,
17148    ) -> Task<Result<Navigated>> {
17149        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17150    }
17151
17152    pub fn go_to_type_definition(
17153        &mut self,
17154        _: &GoToTypeDefinition,
17155        window: &mut Window,
17156        cx: &mut Context<Self>,
17157    ) -> Task<Result<Navigated>> {
17158        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17159    }
17160
17161    pub fn go_to_definition_split(
17162        &mut self,
17163        _: &GoToDefinitionSplit,
17164        window: &mut Window,
17165        cx: &mut Context<Self>,
17166    ) -> Task<Result<Navigated>> {
17167        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17168    }
17169
17170    pub fn go_to_type_definition_split(
17171        &mut self,
17172        _: &GoToTypeDefinitionSplit,
17173        window: &mut Window,
17174        cx: &mut Context<Self>,
17175    ) -> Task<Result<Navigated>> {
17176        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17177    }
17178
17179    fn go_to_definition_of_kind(
17180        &mut self,
17181        kind: GotoDefinitionKind,
17182        split: bool,
17183        window: &mut Window,
17184        cx: &mut Context<Self>,
17185    ) -> Task<Result<Navigated>> {
17186        let Some(provider) = self.semantics_provider.clone() else {
17187            return Task::ready(Ok(Navigated::No));
17188        };
17189        let head = self
17190            .selections
17191            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17192            .head();
17193        let buffer = self.buffer.read(cx);
17194        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17195            return Task::ready(Ok(Navigated::No));
17196        };
17197        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17198            return Task::ready(Ok(Navigated::No));
17199        };
17200
17201        cx.spawn_in(window, async move |editor, cx| {
17202            let Some(definitions) = definitions.await? else {
17203                return Ok(Navigated::No);
17204            };
17205            let navigated = editor
17206                .update_in(cx, |editor, window, cx| {
17207                    editor.navigate_to_hover_links(
17208                        Some(kind),
17209                        definitions
17210                            .into_iter()
17211                            .filter(|location| {
17212                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17213                            })
17214                            .map(HoverLink::Text)
17215                            .collect::<Vec<_>>(),
17216                        split,
17217                        window,
17218                        cx,
17219                    )
17220                })?
17221                .await?;
17222            anyhow::Ok(navigated)
17223        })
17224    }
17225
17226    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17227        let selection = self.selections.newest_anchor();
17228        let head = selection.head();
17229        let tail = selection.tail();
17230
17231        let Some((buffer, start_position)) =
17232            self.buffer.read(cx).text_anchor_for_position(head, cx)
17233        else {
17234            return;
17235        };
17236
17237        let end_position = if head != tail {
17238            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17239                return;
17240            };
17241            Some(pos)
17242        } else {
17243            None
17244        };
17245
17246        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17247            let url = if let Some(end_pos) = end_position {
17248                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17249            } else {
17250                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17251            };
17252
17253            if let Some(url) = url {
17254                cx.update(|window, cx| {
17255                    if parse_zed_link(&url, cx).is_some() {
17256                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17257                    } else {
17258                        cx.open_url(&url);
17259                    }
17260                })?;
17261            }
17262
17263            anyhow::Ok(())
17264        });
17265
17266        url_finder.detach();
17267    }
17268
17269    pub fn open_selected_filename(
17270        &mut self,
17271        _: &OpenSelectedFilename,
17272        window: &mut Window,
17273        cx: &mut Context<Self>,
17274    ) {
17275        let Some(workspace) = self.workspace() else {
17276            return;
17277        };
17278
17279        let position = self.selections.newest_anchor().head();
17280
17281        let Some((buffer, buffer_position)) =
17282            self.buffer.read(cx).text_anchor_for_position(position, cx)
17283        else {
17284            return;
17285        };
17286
17287        let project = self.project.clone();
17288
17289        cx.spawn_in(window, async move |_, cx| {
17290            let result = find_file(&buffer, project, buffer_position, cx).await;
17291
17292            if let Some((_, path)) = result {
17293                workspace
17294                    .update_in(cx, |workspace, window, cx| {
17295                        workspace.open_resolved_path(path, window, cx)
17296                    })?
17297                    .await?;
17298            }
17299            anyhow::Ok(())
17300        })
17301        .detach();
17302    }
17303
17304    pub(crate) fn navigate_to_hover_links(
17305        &mut self,
17306        kind: Option<GotoDefinitionKind>,
17307        definitions: Vec<HoverLink>,
17308        split: bool,
17309        window: &mut Window,
17310        cx: &mut Context<Editor>,
17311    ) -> Task<Result<Navigated>> {
17312        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17313        let mut first_url_or_file = None;
17314        let definitions: Vec<_> = definitions
17315            .into_iter()
17316            .filter_map(|def| match def {
17317                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17318                HoverLink::InlayHint(lsp_location, server_id) => {
17319                    let computation =
17320                        self.compute_target_location(lsp_location, server_id, window, cx);
17321                    Some(cx.background_spawn(computation))
17322                }
17323                HoverLink::Url(url) => {
17324                    first_url_or_file = Some(Either::Left(url));
17325                    None
17326                }
17327                HoverLink::File(path) => {
17328                    first_url_or_file = Some(Either::Right(path));
17329                    None
17330                }
17331            })
17332            .collect();
17333
17334        let workspace = self.workspace();
17335
17336        cx.spawn_in(window, async move |editor, cx| {
17337            let locations: Vec<Location> = future::join_all(definitions)
17338                .await
17339                .into_iter()
17340                .filter_map(|location| location.transpose())
17341                .collect::<Result<_>>()
17342                .context("location tasks")?;
17343            let mut locations = cx.update(|_, cx| {
17344                locations
17345                    .into_iter()
17346                    .map(|location| {
17347                        let buffer = location.buffer.read(cx);
17348                        (location.buffer, location.range.to_point(buffer))
17349                    })
17350                    .into_group_map()
17351            })?;
17352            let mut num_locations = 0;
17353            for ranges in locations.values_mut() {
17354                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17355                ranges.dedup();
17356                num_locations += ranges.len();
17357            }
17358
17359            if num_locations > 1 {
17360                let tab_kind = match kind {
17361                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17362                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17363                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17364                    Some(GotoDefinitionKind::Type) => "Types",
17365                };
17366                let title = editor
17367                    .update_in(cx, |_, _, cx| {
17368                        let target = locations
17369                            .iter()
17370                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17371                            .map(|(buffer, location)| {
17372                                buffer
17373                                    .read(cx)
17374                                    .text_for_range(location.clone())
17375                                    .collect::<String>()
17376                            })
17377                            .filter(|text| !text.contains('\n'))
17378                            .unique()
17379                            .take(3)
17380                            .join(", ");
17381                        if target.is_empty() {
17382                            tab_kind.to_owned()
17383                        } else {
17384                            format!("{tab_kind} for {target}")
17385                        }
17386                    })
17387                    .context("buffer title")?;
17388
17389                let Some(workspace) = workspace else {
17390                    return Ok(Navigated::No);
17391                };
17392
17393                let opened = workspace
17394                    .update_in(cx, |workspace, window, cx| {
17395                        let allow_preview = PreviewTabsSettings::get_global(cx)
17396                            .enable_preview_multibuffer_from_code_navigation;
17397                        Self::open_locations_in_multibuffer(
17398                            workspace,
17399                            locations,
17400                            title,
17401                            split,
17402                            allow_preview,
17403                            MultibufferSelectionMode::First,
17404                            window,
17405                            cx,
17406                        )
17407                    })
17408                    .is_ok();
17409
17410                anyhow::Ok(Navigated::from_bool(opened))
17411            } else if num_locations == 0 {
17412                // If there is one url or file, open it directly
17413                match first_url_or_file {
17414                    Some(Either::Left(url)) => {
17415                        cx.update(|_, cx| cx.open_url(&url))?;
17416                        Ok(Navigated::Yes)
17417                    }
17418                    Some(Either::Right(path)) => {
17419                        // TODO(andrew): respect preview tab settings
17420                        //               `enable_keep_preview_on_code_navigation` and
17421                        //               `enable_preview_file_from_code_navigation`
17422                        let Some(workspace) = workspace else {
17423                            return Ok(Navigated::No);
17424                        };
17425                        workspace
17426                            .update_in(cx, |workspace, window, cx| {
17427                                workspace.open_resolved_path(path, window, cx)
17428                            })?
17429                            .await?;
17430                        Ok(Navigated::Yes)
17431                    }
17432                    None => Ok(Navigated::No),
17433                }
17434            } else {
17435                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17436                let target_range = target_ranges.first().unwrap().clone();
17437
17438                editor.update_in(cx, |editor, window, cx| {
17439                    let range = target_range.to_point(target_buffer.read(cx));
17440                    let range = editor.range_for_match(&range);
17441                    let range = collapse_multiline_range(range);
17442
17443                    if !split
17444                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17445                    {
17446                        editor.go_to_singleton_buffer_range(range, window, cx);
17447                    } else {
17448                        let Some(workspace) = workspace else {
17449                            return Navigated::No;
17450                        };
17451                        let pane = workspace.read(cx).active_pane().clone();
17452                        window.defer(cx, move |window, cx| {
17453                            let target_editor: Entity<Self> =
17454                                workspace.update(cx, |workspace, cx| {
17455                                    let pane = if split {
17456                                        workspace.adjacent_pane(window, cx)
17457                                    } else {
17458                                        workspace.active_pane().clone()
17459                                    };
17460
17461                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17462                                    let keep_old_preview = preview_tabs_settings
17463                                        .enable_keep_preview_on_code_navigation;
17464                                    let allow_new_preview = preview_tabs_settings
17465                                        .enable_preview_file_from_code_navigation;
17466
17467                                    workspace.open_project_item(
17468                                        pane,
17469                                        target_buffer.clone(),
17470                                        true,
17471                                        true,
17472                                        keep_old_preview,
17473                                        allow_new_preview,
17474                                        window,
17475                                        cx,
17476                                    )
17477                                });
17478                            target_editor.update(cx, |target_editor, cx| {
17479                                // When selecting a definition in a different buffer, disable the nav history
17480                                // to avoid creating a history entry at the previous cursor location.
17481                                pane.update(cx, |pane, _| pane.disable_history());
17482                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17483                                pane.update(cx, |pane, _| pane.enable_history());
17484                            });
17485                        });
17486                    }
17487                    Navigated::Yes
17488                })
17489            }
17490        })
17491    }
17492
17493    fn compute_target_location(
17494        &self,
17495        lsp_location: lsp::Location,
17496        server_id: LanguageServerId,
17497        window: &mut Window,
17498        cx: &mut Context<Self>,
17499    ) -> Task<anyhow::Result<Option<Location>>> {
17500        let Some(project) = self.project.clone() else {
17501            return Task::ready(Ok(None));
17502        };
17503
17504        cx.spawn_in(window, async move |editor, cx| {
17505            let location_task = editor.update(cx, |_, cx| {
17506                project.update(cx, |project, cx| {
17507                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17508                })
17509            })?;
17510            let location = Some({
17511                let target_buffer_handle = location_task.await.context("open local buffer")?;
17512                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17513                    let target_start = target_buffer
17514                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17515                    let target_end = target_buffer
17516                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17517                    target_buffer.anchor_after(target_start)
17518                        ..target_buffer.anchor_before(target_end)
17519                })?;
17520                Location {
17521                    buffer: target_buffer_handle,
17522                    range,
17523                }
17524            });
17525            Ok(location)
17526        })
17527    }
17528
17529    fn go_to_next_reference(
17530        &mut self,
17531        _: &GoToNextReference,
17532        window: &mut Window,
17533        cx: &mut Context<Self>,
17534    ) {
17535        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17536        if let Some(task) = task {
17537            task.detach();
17538        };
17539    }
17540
17541    fn go_to_prev_reference(
17542        &mut self,
17543        _: &GoToPreviousReference,
17544        window: &mut Window,
17545        cx: &mut Context<Self>,
17546    ) {
17547        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17548        if let Some(task) = task {
17549            task.detach();
17550        };
17551    }
17552
17553    pub fn go_to_reference_before_or_after_position(
17554        &mut self,
17555        direction: Direction,
17556        count: usize,
17557        window: &mut Window,
17558        cx: &mut Context<Self>,
17559    ) -> Option<Task<Result<()>>> {
17560        let selection = self.selections.newest_anchor();
17561        let head = selection.head();
17562
17563        let multi_buffer = self.buffer.read(cx);
17564
17565        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17566        let workspace = self.workspace()?;
17567        let project = workspace.read(cx).project().clone();
17568        let references =
17569            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17570        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17571            let Some(locations) = references.await? else {
17572                return Ok(());
17573            };
17574
17575            if locations.is_empty() {
17576                // totally normal - the cursor may be on something which is not
17577                // a symbol (e.g. a keyword)
17578                log::info!("no references found under cursor");
17579                return Ok(());
17580            }
17581
17582            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17583
17584            let (locations, current_location_index) =
17585                multi_buffer.update(cx, |multi_buffer, cx| {
17586                    let mut locations = locations
17587                        .into_iter()
17588                        .filter_map(|loc| {
17589                            let start = multi_buffer.buffer_anchor_to_anchor(
17590                                &loc.buffer,
17591                                loc.range.start,
17592                                cx,
17593                            )?;
17594                            let end = multi_buffer.buffer_anchor_to_anchor(
17595                                &loc.buffer,
17596                                loc.range.end,
17597                                cx,
17598                            )?;
17599                            Some(start..end)
17600                        })
17601                        .collect::<Vec<_>>();
17602
17603                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17604                    // There is an O(n) implementation, but given this list will be
17605                    // small (usually <100 items), the extra O(log(n)) factor isn't
17606                    // worth the (surprisingly large amount of) extra complexity.
17607                    locations
17608                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17609
17610                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17611
17612                    let current_location_index = locations.iter().position(|loc| {
17613                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17614                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17615                    });
17616
17617                    (locations, current_location_index)
17618                })?;
17619
17620            let Some(current_location_index) = current_location_index else {
17621                // This indicates something has gone wrong, because we already
17622                // handle the "no references" case above
17623                log::error!(
17624                    "failed to find current reference under cursor. Total references: {}",
17625                    locations.len()
17626                );
17627                return Ok(());
17628            };
17629
17630            let destination_location_index = match direction {
17631                Direction::Next => (current_location_index + count) % locations.len(),
17632                Direction::Prev => {
17633                    (current_location_index + locations.len() - count % locations.len())
17634                        % locations.len()
17635                }
17636            };
17637
17638            // TODO(cameron): is this needed?
17639            // the thinking is to avoid "jumping to the current location" (avoid
17640            // polluting "jumplist" in vim terms)
17641            if current_location_index == destination_location_index {
17642                return Ok(());
17643            }
17644
17645            let Range { start, end } = locations[destination_location_index];
17646
17647            editor.update_in(cx, |editor, window, cx| {
17648                let effects = SelectionEffects::default();
17649
17650                editor.unfold_ranges(&[start..end], false, false, cx);
17651                editor.change_selections(effects, window, cx, |s| {
17652                    s.select_ranges([start..start]);
17653                });
17654            })?;
17655
17656            Ok(())
17657        }))
17658    }
17659
17660    pub fn find_all_references(
17661        &mut self,
17662        action: &FindAllReferences,
17663        window: &mut Window,
17664        cx: &mut Context<Self>,
17665    ) -> Option<Task<Result<Navigated>>> {
17666        let always_open_multibuffer = action.always_open_multibuffer;
17667        let selection = self.selections.newest_anchor();
17668        let multi_buffer = self.buffer.read(cx);
17669        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17670        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
17671        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
17672        let head = selection_offset.head();
17673
17674        let head_anchor = multi_buffer_snapshot.anchor_at(
17675            head,
17676            if head < selection_offset.tail() {
17677                Bias::Right
17678            } else {
17679                Bias::Left
17680            },
17681        );
17682
17683        match self
17684            .find_all_references_task_sources
17685            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17686        {
17687            Ok(_) => {
17688                log::info!(
17689                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17690                );
17691                return None;
17692            }
17693            Err(i) => {
17694                self.find_all_references_task_sources.insert(i, head_anchor);
17695            }
17696        }
17697
17698        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17699        let workspace = self.workspace()?;
17700        let project = workspace.read(cx).project().clone();
17701        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17702        Some(cx.spawn_in(window, async move |editor, cx| {
17703            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17704                if let Ok(i) = editor
17705                    .find_all_references_task_sources
17706                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17707                {
17708                    editor.find_all_references_task_sources.remove(i);
17709                }
17710            });
17711
17712            let Some(locations) = references.await? else {
17713                return anyhow::Ok(Navigated::No);
17714            };
17715            let mut locations = cx.update(|_, cx| {
17716                locations
17717                    .into_iter()
17718                    .map(|location| {
17719                        let buffer = location.buffer.read(cx);
17720                        (location.buffer, location.range.to_point(buffer))
17721                    })
17722                    // if special-casing the single-match case, remove ranges
17723                    // that intersect current selection
17724                    .filter(|(location_buffer, location)| {
17725                        if always_open_multibuffer || &buffer != location_buffer {
17726                            return true;
17727                        }
17728
17729                        !location.contains_inclusive(&selection_point.range())
17730                    })
17731                    .into_group_map()
17732            })?;
17733            if locations.is_empty() {
17734                return anyhow::Ok(Navigated::No);
17735            }
17736            for ranges in locations.values_mut() {
17737                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17738                ranges.dedup();
17739            }
17740            let mut num_locations = 0;
17741            for ranges in locations.values_mut() {
17742                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17743                ranges.dedup();
17744                num_locations += ranges.len();
17745            }
17746
17747            if num_locations == 1 && !always_open_multibuffer {
17748                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17749                let target_range = target_ranges.first().unwrap().clone();
17750
17751                return editor.update_in(cx, |editor, window, cx| {
17752                    let range = target_range.to_point(target_buffer.read(cx));
17753                    let range = editor.range_for_match(&range);
17754                    let range = range.start..range.start;
17755
17756                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
17757                        editor.go_to_singleton_buffer_range(range, window, cx);
17758                    } else {
17759                        let pane = workspace.read(cx).active_pane().clone();
17760                        window.defer(cx, move |window, cx| {
17761                            let target_editor: Entity<Self> =
17762                                workspace.update(cx, |workspace, cx| {
17763                                    let pane = workspace.active_pane().clone();
17764
17765                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17766                                    let keep_old_preview = preview_tabs_settings
17767                                        .enable_keep_preview_on_code_navigation;
17768                                    let allow_new_preview = preview_tabs_settings
17769                                        .enable_preview_file_from_code_navigation;
17770
17771                                    workspace.open_project_item(
17772                                        pane,
17773                                        target_buffer.clone(),
17774                                        true,
17775                                        true,
17776                                        keep_old_preview,
17777                                        allow_new_preview,
17778                                        window,
17779                                        cx,
17780                                    )
17781                                });
17782                            target_editor.update(cx, |target_editor, cx| {
17783                                // When selecting a definition in a different buffer, disable the nav history
17784                                // to avoid creating a history entry at the previous cursor location.
17785                                pane.update(cx, |pane, _| pane.disable_history());
17786                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17787                                pane.update(cx, |pane, _| pane.enable_history());
17788                            });
17789                        });
17790                    }
17791                    Navigated::No
17792                });
17793            }
17794
17795            workspace.update_in(cx, |workspace, window, cx| {
17796                let target = locations
17797                    .iter()
17798                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17799                    .map(|(buffer, location)| {
17800                        buffer
17801                            .read(cx)
17802                            .text_for_range(location.clone())
17803                            .collect::<String>()
17804                    })
17805                    .filter(|text| !text.contains('\n'))
17806                    .unique()
17807                    .take(3)
17808                    .join(", ");
17809                let title = if target.is_empty() {
17810                    "References".to_owned()
17811                } else {
17812                    format!("References to {target}")
17813                };
17814                let allow_preview = PreviewTabsSettings::get_global(cx)
17815                    .enable_preview_multibuffer_from_code_navigation;
17816                Self::open_locations_in_multibuffer(
17817                    workspace,
17818                    locations,
17819                    title,
17820                    false,
17821                    allow_preview,
17822                    MultibufferSelectionMode::First,
17823                    window,
17824                    cx,
17825                );
17826                Navigated::Yes
17827            })
17828        }))
17829    }
17830
17831    /// Opens a multibuffer with the given project locations in it.
17832    pub fn open_locations_in_multibuffer(
17833        workspace: &mut Workspace,
17834        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17835        title: String,
17836        split: bool,
17837        allow_preview: bool,
17838        multibuffer_selection_mode: MultibufferSelectionMode,
17839        window: &mut Window,
17840        cx: &mut Context<Workspace>,
17841    ) {
17842        if locations.is_empty() {
17843            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17844            return;
17845        }
17846
17847        let capability = workspace.project().read(cx).capability();
17848        let mut ranges = <Vec<Range<Anchor>>>::new();
17849
17850        // a key to find existing multibuffer editors with the same set of locations
17851        // to prevent us from opening more and more multibuffer tabs for searches and the like
17852        let mut key = (title.clone(), vec![]);
17853        let excerpt_buffer = cx.new(|cx| {
17854            let key = &mut key.1;
17855            let mut multibuffer = MultiBuffer::new(capability);
17856            for (buffer, mut ranges_for_buffer) in locations {
17857                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17858                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17859                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17860                    PathKey::for_buffer(&buffer, cx),
17861                    buffer.clone(),
17862                    ranges_for_buffer,
17863                    multibuffer_context_lines(cx),
17864                    cx,
17865                );
17866                ranges.extend(new_ranges)
17867            }
17868
17869            multibuffer.with_title(title)
17870        });
17871        let existing = workspace.active_pane().update(cx, |pane, cx| {
17872            pane.items()
17873                .filter_map(|item| item.downcast::<Editor>())
17874                .find(|editor| {
17875                    editor
17876                        .read(cx)
17877                        .lookup_key
17878                        .as_ref()
17879                        .and_then(|it| {
17880                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17881                        })
17882                        .is_some_and(|it| *it == key)
17883                })
17884        });
17885        let was_existing = existing.is_some();
17886        let editor = existing.unwrap_or_else(|| {
17887            cx.new(|cx| {
17888                let mut editor = Editor::for_multibuffer(
17889                    excerpt_buffer,
17890                    Some(workspace.project().clone()),
17891                    window,
17892                    cx,
17893                );
17894                editor.lookup_key = Some(Box::new(key));
17895                editor
17896            })
17897        });
17898        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17899            MultibufferSelectionMode::First => {
17900                if let Some(first_range) = ranges.first() {
17901                    editor.change_selections(
17902                        SelectionEffects::no_scroll(),
17903                        window,
17904                        cx,
17905                        |selections| {
17906                            selections.clear_disjoint();
17907                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17908                        },
17909                    );
17910                }
17911                editor.highlight_background::<Self>(
17912                    &ranges,
17913                    |_, theme| theme.colors().editor_highlighted_line_background,
17914                    cx,
17915                );
17916            }
17917            MultibufferSelectionMode::All => {
17918                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17919                    selections.clear_disjoint();
17920                    selections.select_anchor_ranges(ranges);
17921                });
17922            }
17923        });
17924
17925        let item = Box::new(editor);
17926
17927        let pane = if split {
17928            workspace.adjacent_pane(window, cx)
17929        } else {
17930            workspace.active_pane().clone()
17931        };
17932        let activate_pane = split;
17933
17934        let mut destination_index = None;
17935        pane.update(cx, |pane, cx| {
17936            if allow_preview && !was_existing {
17937                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
17938            }
17939            if was_existing && !allow_preview {
17940                pane.unpreview_item_if_preview(item.item_id());
17941            }
17942            pane.add_item(item, activate_pane, true, destination_index, window, cx);
17943        });
17944    }
17945
17946    pub fn rename(
17947        &mut self,
17948        _: &Rename,
17949        window: &mut Window,
17950        cx: &mut Context<Self>,
17951    ) -> Option<Task<Result<()>>> {
17952        use language::ToOffset as _;
17953
17954        let provider = self.semantics_provider.clone()?;
17955        let selection = self.selections.newest_anchor().clone();
17956        let (cursor_buffer, cursor_buffer_position) = self
17957            .buffer
17958            .read(cx)
17959            .text_anchor_for_position(selection.head(), cx)?;
17960        let (tail_buffer, cursor_buffer_position_end) = self
17961            .buffer
17962            .read(cx)
17963            .text_anchor_for_position(selection.tail(), cx)?;
17964        if tail_buffer != cursor_buffer {
17965            return None;
17966        }
17967
17968        let snapshot = cursor_buffer.read(cx).snapshot();
17969        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17970        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17971        let prepare_rename = provider
17972            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17973            .unwrap_or_else(|| Task::ready(Ok(None)));
17974        drop(snapshot);
17975
17976        Some(cx.spawn_in(window, async move |this, cx| {
17977            let rename_range = if let Some(range) = prepare_rename.await? {
17978                Some(range)
17979            } else {
17980                this.update(cx, |this, cx| {
17981                    let buffer = this.buffer.read(cx).snapshot(cx);
17982                    let mut buffer_highlights = this
17983                        .document_highlights_for_position(selection.head(), &buffer)
17984                        .filter(|highlight| {
17985                            highlight.start.excerpt_id == selection.head().excerpt_id
17986                                && highlight.end.excerpt_id == selection.head().excerpt_id
17987                        });
17988                    buffer_highlights
17989                        .next()
17990                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17991                })?
17992            };
17993            if let Some(rename_range) = rename_range {
17994                this.update_in(cx, |this, window, cx| {
17995                    let snapshot = cursor_buffer.read(cx).snapshot();
17996                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17997                    let cursor_offset_in_rename_range =
17998                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17999                    let cursor_offset_in_rename_range_end =
18000                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
18001
18002                    this.take_rename(false, window, cx);
18003                    let buffer = this.buffer.read(cx).read(cx);
18004                    let cursor_offset = selection.head().to_offset(&buffer);
18005                    let rename_start =
18006                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
18007                    let rename_end = rename_start + rename_buffer_range.len();
18008                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
18009                    let mut old_highlight_id = None;
18010                    let old_name: Arc<str> = buffer
18011                        .chunks(rename_start..rename_end, true)
18012                        .map(|chunk| {
18013                            if old_highlight_id.is_none() {
18014                                old_highlight_id = chunk.syntax_highlight_id;
18015                            }
18016                            chunk.text
18017                        })
18018                        .collect::<String>()
18019                        .into();
18020
18021                    drop(buffer);
18022
18023                    // Position the selection in the rename editor so that it matches the current selection.
18024                    this.show_local_selections = false;
18025                    let rename_editor = cx.new(|cx| {
18026                        let mut editor = Editor::single_line(window, cx);
18027                        editor.buffer.update(cx, |buffer, cx| {
18028                            buffer.edit(
18029                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18030                                None,
18031                                cx,
18032                            )
18033                        });
18034                        let cursor_offset_in_rename_range =
18035                            MultiBufferOffset(cursor_offset_in_rename_range);
18036                        let cursor_offset_in_rename_range_end =
18037                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18038                        let rename_selection_range = match cursor_offset_in_rename_range
18039                            .cmp(&cursor_offset_in_rename_range_end)
18040                        {
18041                            Ordering::Equal => {
18042                                editor.select_all(&SelectAll, window, cx);
18043                                return editor;
18044                            }
18045                            Ordering::Less => {
18046                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18047                            }
18048                            Ordering::Greater => {
18049                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18050                            }
18051                        };
18052                        if rename_selection_range.end.0 > old_name.len() {
18053                            editor.select_all(&SelectAll, window, cx);
18054                        } else {
18055                            editor.change_selections(Default::default(), window, cx, |s| {
18056                                s.select_ranges([rename_selection_range]);
18057                            });
18058                        }
18059                        editor
18060                    });
18061                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18062                        if e == &EditorEvent::Focused {
18063                            cx.emit(EditorEvent::FocusedIn)
18064                        }
18065                    })
18066                    .detach();
18067
18068                    let write_highlights =
18069                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18070                    let read_highlights =
18071                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18072                    let ranges = write_highlights
18073                        .iter()
18074                        .flat_map(|(_, ranges)| ranges.iter())
18075                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18076                        .cloned()
18077                        .collect();
18078
18079                    this.highlight_text::<Rename>(
18080                        ranges,
18081                        HighlightStyle {
18082                            fade_out: Some(0.6),
18083                            ..Default::default()
18084                        },
18085                        cx,
18086                    );
18087                    let rename_focus_handle = rename_editor.focus_handle(cx);
18088                    window.focus(&rename_focus_handle);
18089                    let block_id = this.insert_blocks(
18090                        [BlockProperties {
18091                            style: BlockStyle::Flex,
18092                            placement: BlockPlacement::Below(range.start),
18093                            height: Some(1),
18094                            render: Arc::new({
18095                                let rename_editor = rename_editor.clone();
18096                                move |cx: &mut BlockContext| {
18097                                    let mut text_style = cx.editor_style.text.clone();
18098                                    if let Some(highlight_style) = old_highlight_id
18099                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18100                                    {
18101                                        text_style = text_style.highlight(highlight_style);
18102                                    }
18103                                    div()
18104                                        .block_mouse_except_scroll()
18105                                        .pl(cx.anchor_x)
18106                                        .child(EditorElement::new(
18107                                            &rename_editor,
18108                                            EditorStyle {
18109                                                background: cx.theme().system().transparent,
18110                                                local_player: cx.editor_style.local_player,
18111                                                text: text_style,
18112                                                scrollbar_width: cx.editor_style.scrollbar_width,
18113                                                syntax: cx.editor_style.syntax.clone(),
18114                                                status: cx.editor_style.status.clone(),
18115                                                inlay_hints_style: HighlightStyle {
18116                                                    font_weight: Some(FontWeight::BOLD),
18117                                                    ..make_inlay_hints_style(cx.app)
18118                                                },
18119                                                edit_prediction_styles: make_suggestion_styles(
18120                                                    cx.app,
18121                                                ),
18122                                                ..EditorStyle::default()
18123                                            },
18124                                        ))
18125                                        .into_any_element()
18126                                }
18127                            }),
18128                            priority: 0,
18129                        }],
18130                        Some(Autoscroll::fit()),
18131                        cx,
18132                    )[0];
18133                    this.pending_rename = Some(RenameState {
18134                        range,
18135                        old_name,
18136                        editor: rename_editor,
18137                        block_id,
18138                    });
18139                })?;
18140            }
18141
18142            Ok(())
18143        }))
18144    }
18145
18146    pub fn confirm_rename(
18147        &mut self,
18148        _: &ConfirmRename,
18149        window: &mut Window,
18150        cx: &mut Context<Self>,
18151    ) -> Option<Task<Result<()>>> {
18152        let rename = self.take_rename(false, window, cx)?;
18153        let workspace = self.workspace()?.downgrade();
18154        let (buffer, start) = self
18155            .buffer
18156            .read(cx)
18157            .text_anchor_for_position(rename.range.start, cx)?;
18158        let (end_buffer, _) = self
18159            .buffer
18160            .read(cx)
18161            .text_anchor_for_position(rename.range.end, cx)?;
18162        if buffer != end_buffer {
18163            return None;
18164        }
18165
18166        let old_name = rename.old_name;
18167        let new_name = rename.editor.read(cx).text(cx);
18168
18169        let rename = self.semantics_provider.as_ref()?.perform_rename(
18170            &buffer,
18171            start,
18172            new_name.clone(),
18173            cx,
18174        )?;
18175
18176        Some(cx.spawn_in(window, async move |editor, cx| {
18177            let project_transaction = rename.await?;
18178            Self::open_project_transaction(
18179                &editor,
18180                workspace,
18181                project_transaction,
18182                format!("Rename: {}{}", old_name, new_name),
18183                cx,
18184            )
18185            .await?;
18186
18187            editor.update(cx, |editor, cx| {
18188                editor.refresh_document_highlights(cx);
18189            })?;
18190            Ok(())
18191        }))
18192    }
18193
18194    fn take_rename(
18195        &mut self,
18196        moving_cursor: bool,
18197        window: &mut Window,
18198        cx: &mut Context<Self>,
18199    ) -> Option<RenameState> {
18200        let rename = self.pending_rename.take()?;
18201        if rename.editor.focus_handle(cx).is_focused(window) {
18202            window.focus(&self.focus_handle);
18203        }
18204
18205        self.remove_blocks(
18206            [rename.block_id].into_iter().collect(),
18207            Some(Autoscroll::fit()),
18208            cx,
18209        );
18210        self.clear_highlights::<Rename>(cx);
18211        self.show_local_selections = true;
18212
18213        if moving_cursor {
18214            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18215                editor
18216                    .selections
18217                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18218                    .head()
18219            });
18220
18221            // Update the selection to match the position of the selection inside
18222            // the rename editor.
18223            let snapshot = self.buffer.read(cx).read(cx);
18224            let rename_range = rename.range.to_offset(&snapshot);
18225            let cursor_in_editor = snapshot
18226                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18227                .min(rename_range.end);
18228            drop(snapshot);
18229
18230            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18231                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18232            });
18233        } else {
18234            self.refresh_document_highlights(cx);
18235        }
18236
18237        Some(rename)
18238    }
18239
18240    pub fn pending_rename(&self) -> Option<&RenameState> {
18241        self.pending_rename.as_ref()
18242    }
18243
18244    fn format(
18245        &mut self,
18246        _: &Format,
18247        window: &mut Window,
18248        cx: &mut Context<Self>,
18249    ) -> Option<Task<Result<()>>> {
18250        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18251
18252        let project = match &self.project {
18253            Some(project) => project.clone(),
18254            None => return None,
18255        };
18256
18257        Some(self.perform_format(
18258            project,
18259            FormatTrigger::Manual,
18260            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18261            window,
18262            cx,
18263        ))
18264    }
18265
18266    fn format_selections(
18267        &mut self,
18268        _: &FormatSelections,
18269        window: &mut Window,
18270        cx: &mut Context<Self>,
18271    ) -> Option<Task<Result<()>>> {
18272        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18273
18274        let project = match &self.project {
18275            Some(project) => project.clone(),
18276            None => return None,
18277        };
18278
18279        let ranges = self
18280            .selections
18281            .all_adjusted(&self.display_snapshot(cx))
18282            .into_iter()
18283            .map(|selection| selection.range())
18284            .collect_vec();
18285
18286        Some(self.perform_format(
18287            project,
18288            FormatTrigger::Manual,
18289            FormatTarget::Ranges(ranges),
18290            window,
18291            cx,
18292        ))
18293    }
18294
18295    fn perform_format(
18296        &mut self,
18297        project: Entity<Project>,
18298        trigger: FormatTrigger,
18299        target: FormatTarget,
18300        window: &mut Window,
18301        cx: &mut Context<Self>,
18302    ) -> Task<Result<()>> {
18303        let buffer = self.buffer.clone();
18304        let (buffers, target) = match target {
18305            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18306            FormatTarget::Ranges(selection_ranges) => {
18307                let multi_buffer = buffer.read(cx);
18308                let snapshot = multi_buffer.read(cx);
18309                let mut buffers = HashSet::default();
18310                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18311                    BTreeMap::new();
18312                for selection_range in selection_ranges {
18313                    for (buffer, buffer_range, _) in
18314                        snapshot.range_to_buffer_ranges(selection_range)
18315                    {
18316                        let buffer_id = buffer.remote_id();
18317                        let start = buffer.anchor_before(buffer_range.start);
18318                        let end = buffer.anchor_after(buffer_range.end);
18319                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18320                        buffer_id_to_ranges
18321                            .entry(buffer_id)
18322                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18323                            .or_insert_with(|| vec![start..end]);
18324                    }
18325                }
18326                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18327            }
18328        };
18329
18330        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18331        let selections_prev = transaction_id_prev
18332            .and_then(|transaction_id_prev| {
18333                // default to selections as they were after the last edit, if we have them,
18334                // instead of how they are now.
18335                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18336                // will take you back to where you made the last edit, instead of staying where you scrolled
18337                self.selection_history
18338                    .transaction(transaction_id_prev)
18339                    .map(|t| t.0.clone())
18340            })
18341            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18342
18343        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18344        let format = project.update(cx, |project, cx| {
18345            project.format(buffers, target, true, trigger, cx)
18346        });
18347
18348        cx.spawn_in(window, async move |editor, cx| {
18349            let transaction = futures::select_biased! {
18350                transaction = format.log_err().fuse() => transaction,
18351                () = timeout => {
18352                    log::warn!("timed out waiting for formatting");
18353                    None
18354                }
18355            };
18356
18357            buffer
18358                .update(cx, |buffer, cx| {
18359                    if let Some(transaction) = transaction
18360                        && !buffer.is_singleton()
18361                    {
18362                        buffer.push_transaction(&transaction.0, cx);
18363                    }
18364                    cx.notify();
18365                })
18366                .ok();
18367
18368            if let Some(transaction_id_now) =
18369                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
18370            {
18371                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18372                if has_new_transaction {
18373                    _ = editor.update(cx, |editor, _| {
18374                        editor
18375                            .selection_history
18376                            .insert_transaction(transaction_id_now, selections_prev);
18377                    });
18378                }
18379            }
18380
18381            Ok(())
18382        })
18383    }
18384
18385    fn organize_imports(
18386        &mut self,
18387        _: &OrganizeImports,
18388        window: &mut Window,
18389        cx: &mut Context<Self>,
18390    ) -> Option<Task<Result<()>>> {
18391        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18392        let project = match &self.project {
18393            Some(project) => project.clone(),
18394            None => return None,
18395        };
18396        Some(self.perform_code_action_kind(
18397            project,
18398            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18399            window,
18400            cx,
18401        ))
18402    }
18403
18404    fn perform_code_action_kind(
18405        &mut self,
18406        project: Entity<Project>,
18407        kind: CodeActionKind,
18408        window: &mut Window,
18409        cx: &mut Context<Self>,
18410    ) -> Task<Result<()>> {
18411        let buffer = self.buffer.clone();
18412        let buffers = buffer.read(cx).all_buffers();
18413        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18414        let apply_action = project.update(cx, |project, cx| {
18415            project.apply_code_action_kind(buffers, kind, true, cx)
18416        });
18417        cx.spawn_in(window, async move |_, cx| {
18418            let transaction = futures::select_biased! {
18419                () = timeout => {
18420                    log::warn!("timed out waiting for executing code action");
18421                    None
18422                }
18423                transaction = apply_action.log_err().fuse() => transaction,
18424            };
18425            buffer
18426                .update(cx, |buffer, cx| {
18427                    // check if we need this
18428                    if let Some(transaction) = transaction
18429                        && !buffer.is_singleton()
18430                    {
18431                        buffer.push_transaction(&transaction.0, cx);
18432                    }
18433                    cx.notify();
18434                })
18435                .ok();
18436            Ok(())
18437        })
18438    }
18439
18440    pub fn restart_language_server(
18441        &mut self,
18442        _: &RestartLanguageServer,
18443        _: &mut Window,
18444        cx: &mut Context<Self>,
18445    ) {
18446        if let Some(project) = self.project.clone() {
18447            self.buffer.update(cx, |multi_buffer, cx| {
18448                project.update(cx, |project, cx| {
18449                    project.restart_language_servers_for_buffers(
18450                        multi_buffer.all_buffers().into_iter().collect(),
18451                        HashSet::default(),
18452                        cx,
18453                    );
18454                });
18455            })
18456        }
18457    }
18458
18459    pub fn stop_language_server(
18460        &mut self,
18461        _: &StopLanguageServer,
18462        _: &mut Window,
18463        cx: &mut Context<Self>,
18464    ) {
18465        if let Some(project) = self.project.clone() {
18466            self.buffer.update(cx, |multi_buffer, cx| {
18467                project.update(cx, |project, cx| {
18468                    project.stop_language_servers_for_buffers(
18469                        multi_buffer.all_buffers().into_iter().collect(),
18470                        HashSet::default(),
18471                        cx,
18472                    );
18473                });
18474            });
18475            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18476        }
18477    }
18478
18479    fn cancel_language_server_work(
18480        workspace: &mut Workspace,
18481        _: &actions::CancelLanguageServerWork,
18482        _: &mut Window,
18483        cx: &mut Context<Workspace>,
18484    ) {
18485        let project = workspace.project();
18486        let buffers = workspace
18487            .active_item(cx)
18488            .and_then(|item| item.act_as::<Editor>(cx))
18489            .map_or(HashSet::default(), |editor| {
18490                editor.read(cx).buffer.read(cx).all_buffers()
18491            });
18492        project.update(cx, |project, cx| {
18493            project.cancel_language_server_work_for_buffers(buffers, cx);
18494        });
18495    }
18496
18497    fn show_character_palette(
18498        &mut self,
18499        _: &ShowCharacterPalette,
18500        window: &mut Window,
18501        _: &mut Context<Self>,
18502    ) {
18503        window.show_character_palette();
18504    }
18505
18506    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18507        if !self.diagnostics_enabled() {
18508            return;
18509        }
18510
18511        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18512            let buffer = self.buffer.read(cx).snapshot(cx);
18513            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18514            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18515            let is_valid = buffer
18516                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18517                .any(|entry| {
18518                    entry.diagnostic.is_primary
18519                        && !entry.range.is_empty()
18520                        && entry.range.start == primary_range_start
18521                        && entry.diagnostic.message == active_diagnostics.active_message
18522                });
18523
18524            if !is_valid {
18525                self.dismiss_diagnostics(cx);
18526            }
18527        }
18528    }
18529
18530    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18531        match &self.active_diagnostics {
18532            ActiveDiagnostic::Group(group) => Some(group),
18533            _ => None,
18534        }
18535    }
18536
18537    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18538        if !self.diagnostics_enabled() {
18539            return;
18540        }
18541        self.dismiss_diagnostics(cx);
18542        self.active_diagnostics = ActiveDiagnostic::All;
18543    }
18544
18545    fn activate_diagnostics(
18546        &mut self,
18547        buffer_id: BufferId,
18548        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18549        window: &mut Window,
18550        cx: &mut Context<Self>,
18551    ) {
18552        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18553            return;
18554        }
18555        self.dismiss_diagnostics(cx);
18556        let snapshot = self.snapshot(window, cx);
18557        let buffer = self.buffer.read(cx).snapshot(cx);
18558        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18559            return;
18560        };
18561
18562        let diagnostic_group = buffer
18563            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18564            .collect::<Vec<_>>();
18565
18566        let language_registry = self
18567            .project()
18568            .map(|project| project.read(cx).languages().clone());
18569
18570        let blocks = renderer.render_group(
18571            diagnostic_group,
18572            buffer_id,
18573            snapshot,
18574            cx.weak_entity(),
18575            language_registry,
18576            cx,
18577        );
18578
18579        let blocks = self.display_map.update(cx, |display_map, cx| {
18580            display_map.insert_blocks(blocks, cx).into_iter().collect()
18581        });
18582        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18583            active_range: buffer.anchor_before(diagnostic.range.start)
18584                ..buffer.anchor_after(diagnostic.range.end),
18585            active_message: diagnostic.diagnostic.message.clone(),
18586            group_id: diagnostic.diagnostic.group_id,
18587            blocks,
18588        });
18589        cx.notify();
18590    }
18591
18592    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18593        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18594            return;
18595        };
18596
18597        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18598        if let ActiveDiagnostic::Group(group) = prev {
18599            self.display_map.update(cx, |display_map, cx| {
18600                display_map.remove_blocks(group.blocks, cx);
18601            });
18602            cx.notify();
18603        }
18604    }
18605
18606    /// Disable inline diagnostics rendering for this editor.
18607    pub fn disable_inline_diagnostics(&mut self) {
18608        self.inline_diagnostics_enabled = false;
18609        self.inline_diagnostics_update = Task::ready(());
18610        self.inline_diagnostics.clear();
18611    }
18612
18613    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18614        self.diagnostics_enabled = false;
18615        self.dismiss_diagnostics(cx);
18616        self.inline_diagnostics_update = Task::ready(());
18617        self.inline_diagnostics.clear();
18618    }
18619
18620    pub fn disable_word_completions(&mut self) {
18621        self.word_completions_enabled = false;
18622    }
18623
18624    pub fn diagnostics_enabled(&self) -> bool {
18625        self.diagnostics_enabled && self.mode.is_full()
18626    }
18627
18628    pub fn inline_diagnostics_enabled(&self) -> bool {
18629        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18630    }
18631
18632    pub fn show_inline_diagnostics(&self) -> bool {
18633        self.show_inline_diagnostics
18634    }
18635
18636    pub fn toggle_inline_diagnostics(
18637        &mut self,
18638        _: &ToggleInlineDiagnostics,
18639        window: &mut Window,
18640        cx: &mut Context<Editor>,
18641    ) {
18642        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18643        self.refresh_inline_diagnostics(false, window, cx);
18644    }
18645
18646    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18647        self.diagnostics_max_severity = severity;
18648        self.display_map.update(cx, |display_map, _| {
18649            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18650        });
18651    }
18652
18653    pub fn toggle_diagnostics(
18654        &mut self,
18655        _: &ToggleDiagnostics,
18656        window: &mut Window,
18657        cx: &mut Context<Editor>,
18658    ) {
18659        if !self.diagnostics_enabled() {
18660            return;
18661        }
18662
18663        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18664            EditorSettings::get_global(cx)
18665                .diagnostics_max_severity
18666                .filter(|severity| severity != &DiagnosticSeverity::Off)
18667                .unwrap_or(DiagnosticSeverity::Hint)
18668        } else {
18669            DiagnosticSeverity::Off
18670        };
18671        self.set_max_diagnostics_severity(new_severity, cx);
18672        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18673            self.active_diagnostics = ActiveDiagnostic::None;
18674            self.inline_diagnostics_update = Task::ready(());
18675            self.inline_diagnostics.clear();
18676        } else {
18677            self.refresh_inline_diagnostics(false, window, cx);
18678        }
18679
18680        cx.notify();
18681    }
18682
18683    pub fn toggle_minimap(
18684        &mut self,
18685        _: &ToggleMinimap,
18686        window: &mut Window,
18687        cx: &mut Context<Editor>,
18688    ) {
18689        if self.supports_minimap(cx) {
18690            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18691        }
18692    }
18693
18694    fn refresh_inline_diagnostics(
18695        &mut self,
18696        debounce: bool,
18697        window: &mut Window,
18698        cx: &mut Context<Self>,
18699    ) {
18700        let max_severity = ProjectSettings::get_global(cx)
18701            .diagnostics
18702            .inline
18703            .max_severity
18704            .unwrap_or(self.diagnostics_max_severity);
18705
18706        if !self.inline_diagnostics_enabled()
18707            || !self.diagnostics_enabled()
18708            || !self.show_inline_diagnostics
18709            || max_severity == DiagnosticSeverity::Off
18710        {
18711            self.inline_diagnostics_update = Task::ready(());
18712            self.inline_diagnostics.clear();
18713            return;
18714        }
18715
18716        let debounce_ms = ProjectSettings::get_global(cx)
18717            .diagnostics
18718            .inline
18719            .update_debounce_ms;
18720        let debounce = if debounce && debounce_ms > 0 {
18721            Some(Duration::from_millis(debounce_ms))
18722        } else {
18723            None
18724        };
18725        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18726            if let Some(debounce) = debounce {
18727                cx.background_executor().timer(debounce).await;
18728            }
18729            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18730                editor
18731                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18732                    .ok()
18733            }) else {
18734                return;
18735            };
18736
18737            let new_inline_diagnostics = cx
18738                .background_spawn(async move {
18739                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18740                    for diagnostic_entry in
18741                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18742                    {
18743                        let message = diagnostic_entry
18744                            .diagnostic
18745                            .message
18746                            .split_once('\n')
18747                            .map(|(line, _)| line)
18748                            .map(SharedString::new)
18749                            .unwrap_or_else(|| {
18750                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18751                            });
18752                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18753                        let (Ok(i) | Err(i)) = inline_diagnostics
18754                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18755                        inline_diagnostics.insert(
18756                            i,
18757                            (
18758                                start_anchor,
18759                                InlineDiagnostic {
18760                                    message,
18761                                    group_id: diagnostic_entry.diagnostic.group_id,
18762                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18763                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18764                                    severity: diagnostic_entry.diagnostic.severity,
18765                                },
18766                            ),
18767                        );
18768                    }
18769                    inline_diagnostics
18770                })
18771                .await;
18772
18773            editor
18774                .update(cx, |editor, cx| {
18775                    editor.inline_diagnostics = new_inline_diagnostics;
18776                    cx.notify();
18777                })
18778                .ok();
18779        });
18780    }
18781
18782    fn pull_diagnostics(
18783        &mut self,
18784        buffer_id: Option<BufferId>,
18785        window: &Window,
18786        cx: &mut Context<Self>,
18787    ) -> Option<()> {
18788        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18789            return None;
18790        }
18791        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18792            .diagnostics
18793            .lsp_pull_diagnostics;
18794        if !pull_diagnostics_settings.enabled {
18795            return None;
18796        }
18797        let project = self.project()?.downgrade();
18798
18799        let mut edited_buffer_ids = HashSet::default();
18800        let mut edited_worktree_ids = HashSet::default();
18801        let edited_buffers = match buffer_id {
18802            Some(buffer_id) => {
18803                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
18804                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
18805                edited_buffer_ids.insert(buffer.read(cx).remote_id());
18806                edited_worktree_ids.insert(worktree_id);
18807                vec![buffer]
18808            }
18809            None => self
18810                .buffer()
18811                .read(cx)
18812                .all_buffers()
18813                .into_iter()
18814                .filter(|buffer| {
18815                    let buffer = buffer.read(cx);
18816                    match buffer.file().map(|f| f.worktree_id(cx)) {
18817                        Some(worktree_id) => {
18818                            edited_buffer_ids.insert(buffer.remote_id());
18819                            edited_worktree_ids.insert(worktree_id);
18820                            true
18821                        }
18822                        None => false,
18823                    }
18824                })
18825                .collect::<Vec<_>>(),
18826        };
18827
18828        if edited_buffers.is_empty() {
18829            self.pull_diagnostics_task = Task::ready(());
18830            self.pull_diagnostics_background_task = Task::ready(());
18831            return None;
18832        }
18833
18834        let mut already_used_buffers = HashSet::default();
18835        let related_open_buffers = self
18836            .workspace
18837            .as_ref()
18838            .and_then(|(workspace, _)| workspace.upgrade())
18839            .into_iter()
18840            .flat_map(|workspace| workspace.read(cx).panes())
18841            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
18842            .filter(|editor| editor != &cx.entity())
18843            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
18844            .filter(|buffer| {
18845                let buffer = buffer.read(cx);
18846                let buffer_id = buffer.remote_id();
18847                if already_used_buffers.insert(buffer_id) {
18848                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
18849                        return !edited_buffer_ids.contains(&buffer_id)
18850                            && !edited_worktree_ids.contains(&worktree_id);
18851                    }
18852                }
18853                false
18854            })
18855            .collect::<Vec<_>>();
18856
18857        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18858        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
18859            if buffers.is_empty() {
18860                return Task::ready(());
18861            }
18862            let project_weak = project.clone();
18863            cx.spawn_in(window, async move |_, cx| {
18864                cx.background_executor().timer(delay).await;
18865
18866                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18867                    buffers
18868                        .into_iter()
18869                        .filter_map(|buffer| {
18870                            project_weak
18871                                .update(cx, |project, cx| {
18872                                    project.lsp_store().update(cx, |lsp_store, cx| {
18873                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18874                                    })
18875                                })
18876                                .ok()
18877                        })
18878                        .collect::<FuturesUnordered<_>>()
18879                }) else {
18880                    return;
18881                };
18882
18883                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18884                    if let Err(e) = pull_task {
18885                        log::error!("Failed to update project diagnostics: {e:#}");
18886                    }
18887                }
18888            })
18889        };
18890
18891        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
18892        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
18893
18894        Some(())
18895    }
18896
18897    pub fn set_selections_from_remote(
18898        &mut self,
18899        selections: Vec<Selection<Anchor>>,
18900        pending_selection: Option<Selection<Anchor>>,
18901        window: &mut Window,
18902        cx: &mut Context<Self>,
18903    ) {
18904        let old_cursor_position = self.selections.newest_anchor().head();
18905        self.selections
18906            .change_with(&self.display_snapshot(cx), |s| {
18907                s.select_anchors(selections);
18908                if let Some(pending_selection) = pending_selection {
18909                    s.set_pending(pending_selection, SelectMode::Character);
18910                } else {
18911                    s.clear_pending();
18912                }
18913            });
18914        self.selections_did_change(
18915            false,
18916            &old_cursor_position,
18917            SelectionEffects::default(),
18918            window,
18919            cx,
18920        );
18921    }
18922
18923    pub fn transact(
18924        &mut self,
18925        window: &mut Window,
18926        cx: &mut Context<Self>,
18927        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18928    ) -> Option<TransactionId> {
18929        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18930            this.start_transaction_at(Instant::now(), window, cx);
18931            update(this, window, cx);
18932            this.end_transaction_at(Instant::now(), cx)
18933        })
18934    }
18935
18936    pub fn start_transaction_at(
18937        &mut self,
18938        now: Instant,
18939        window: &mut Window,
18940        cx: &mut Context<Self>,
18941    ) -> Option<TransactionId> {
18942        self.end_selection(window, cx);
18943        if let Some(tx_id) = self
18944            .buffer
18945            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18946        {
18947            self.selection_history
18948                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18949            cx.emit(EditorEvent::TransactionBegun {
18950                transaction_id: tx_id,
18951            });
18952            Some(tx_id)
18953        } else {
18954            None
18955        }
18956    }
18957
18958    pub fn end_transaction_at(
18959        &mut self,
18960        now: Instant,
18961        cx: &mut Context<Self>,
18962    ) -> Option<TransactionId> {
18963        if let Some(transaction_id) = self
18964            .buffer
18965            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18966        {
18967            if let Some((_, end_selections)) =
18968                self.selection_history.transaction_mut(transaction_id)
18969            {
18970                *end_selections = Some(self.selections.disjoint_anchors_arc());
18971            } else {
18972                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18973            }
18974
18975            cx.emit(EditorEvent::Edited { transaction_id });
18976            Some(transaction_id)
18977        } else {
18978            None
18979        }
18980    }
18981
18982    pub fn modify_transaction_selection_history(
18983        &mut self,
18984        transaction_id: TransactionId,
18985        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18986    ) -> bool {
18987        self.selection_history
18988            .transaction_mut(transaction_id)
18989            .map(modify)
18990            .is_some()
18991    }
18992
18993    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18994        if self.selection_mark_mode {
18995            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18996                s.move_with(|_, sel| {
18997                    sel.collapse_to(sel.head(), SelectionGoal::None);
18998                });
18999            })
19000        }
19001        self.selection_mark_mode = true;
19002        cx.notify();
19003    }
19004
19005    pub fn swap_selection_ends(
19006        &mut self,
19007        _: &actions::SwapSelectionEnds,
19008        window: &mut Window,
19009        cx: &mut Context<Self>,
19010    ) {
19011        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19012            s.move_with(|_, sel| {
19013                if sel.start != sel.end {
19014                    sel.reversed = !sel.reversed
19015                }
19016            });
19017        });
19018        self.request_autoscroll(Autoscroll::newest(), cx);
19019        cx.notify();
19020    }
19021
19022    pub fn toggle_focus(
19023        workspace: &mut Workspace,
19024        _: &actions::ToggleFocus,
19025        window: &mut Window,
19026        cx: &mut Context<Workspace>,
19027    ) {
19028        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19029            return;
19030        };
19031        workspace.activate_item(&item, true, true, window, cx);
19032    }
19033
19034    pub fn toggle_fold(
19035        &mut self,
19036        _: &actions::ToggleFold,
19037        window: &mut Window,
19038        cx: &mut Context<Self>,
19039    ) {
19040        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19041            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19042            let selection = self.selections.newest::<Point>(&display_map);
19043
19044            let range = if selection.is_empty() {
19045                let point = selection.head().to_display_point(&display_map);
19046                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19047                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19048                    .to_point(&display_map);
19049                start..end
19050            } else {
19051                selection.range()
19052            };
19053            if display_map.folds_in_range(range).next().is_some() {
19054                self.unfold_lines(&Default::default(), window, cx)
19055            } else {
19056                self.fold(&Default::default(), window, cx)
19057            }
19058        } else {
19059            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19060            let buffer_ids: HashSet<_> = self
19061                .selections
19062                .disjoint_anchor_ranges()
19063                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19064                .collect();
19065
19066            let should_unfold = buffer_ids
19067                .iter()
19068                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19069
19070            for buffer_id in buffer_ids {
19071                if should_unfold {
19072                    self.unfold_buffer(buffer_id, cx);
19073                } else {
19074                    self.fold_buffer(buffer_id, cx);
19075                }
19076            }
19077        }
19078    }
19079
19080    pub fn toggle_fold_recursive(
19081        &mut self,
19082        _: &actions::ToggleFoldRecursive,
19083        window: &mut Window,
19084        cx: &mut Context<Self>,
19085    ) {
19086        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19087
19088        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19089        let range = if selection.is_empty() {
19090            let point = selection.head().to_display_point(&display_map);
19091            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19092            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19093                .to_point(&display_map);
19094            start..end
19095        } else {
19096            selection.range()
19097        };
19098        if display_map.folds_in_range(range).next().is_some() {
19099            self.unfold_recursive(&Default::default(), window, cx)
19100        } else {
19101            self.fold_recursive(&Default::default(), window, cx)
19102        }
19103    }
19104
19105    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19106        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19107            let mut to_fold = Vec::new();
19108            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19109            let selections = self.selections.all_adjusted(&display_map);
19110
19111            for selection in selections {
19112                let range = selection.range().sorted();
19113                let buffer_start_row = range.start.row;
19114
19115                if range.start.row != range.end.row {
19116                    let mut found = false;
19117                    let mut row = range.start.row;
19118                    while row <= range.end.row {
19119                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19120                        {
19121                            found = true;
19122                            row = crease.range().end.row + 1;
19123                            to_fold.push(crease);
19124                        } else {
19125                            row += 1
19126                        }
19127                    }
19128                    if found {
19129                        continue;
19130                    }
19131                }
19132
19133                for row in (0..=range.start.row).rev() {
19134                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19135                        && crease.range().end.row >= buffer_start_row
19136                    {
19137                        to_fold.push(crease);
19138                        if row <= range.start.row {
19139                            break;
19140                        }
19141                    }
19142                }
19143            }
19144
19145            self.fold_creases(to_fold, true, window, cx);
19146        } else {
19147            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19148            let buffer_ids = self
19149                .selections
19150                .disjoint_anchor_ranges()
19151                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19152                .collect::<HashSet<_>>();
19153            for buffer_id in buffer_ids {
19154                self.fold_buffer(buffer_id, cx);
19155            }
19156        }
19157    }
19158
19159    pub fn toggle_fold_all(
19160        &mut self,
19161        _: &actions::ToggleFoldAll,
19162        window: &mut Window,
19163        cx: &mut Context<Self>,
19164    ) {
19165        if self.buffer.read(cx).is_singleton() {
19166            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19167            let has_folds = display_map
19168                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19169                .next()
19170                .is_some();
19171
19172            if has_folds {
19173                self.unfold_all(&actions::UnfoldAll, window, cx);
19174            } else {
19175                self.fold_all(&actions::FoldAll, window, cx);
19176            }
19177        } else {
19178            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19179            let should_unfold = buffer_ids
19180                .iter()
19181                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19182
19183            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19184                editor
19185                    .update_in(cx, |editor, _, cx| {
19186                        for buffer_id in buffer_ids {
19187                            if should_unfold {
19188                                editor.unfold_buffer(buffer_id, cx);
19189                            } else {
19190                                editor.fold_buffer(buffer_id, cx);
19191                            }
19192                        }
19193                    })
19194                    .ok();
19195            });
19196        }
19197    }
19198
19199    fn fold_at_level(
19200        &mut self,
19201        fold_at: &FoldAtLevel,
19202        window: &mut Window,
19203        cx: &mut Context<Self>,
19204    ) {
19205        if !self.buffer.read(cx).is_singleton() {
19206            return;
19207        }
19208
19209        let fold_at_level = fold_at.0;
19210        let snapshot = self.buffer.read(cx).snapshot(cx);
19211        let mut to_fold = Vec::new();
19212        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19213
19214        let row_ranges_to_keep: Vec<Range<u32>> = self
19215            .selections
19216            .all::<Point>(&self.display_snapshot(cx))
19217            .into_iter()
19218            .map(|sel| sel.start.row..sel.end.row)
19219            .collect();
19220
19221        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19222            while start_row < end_row {
19223                match self
19224                    .snapshot(window, cx)
19225                    .crease_for_buffer_row(MultiBufferRow(start_row))
19226                {
19227                    Some(crease) => {
19228                        let nested_start_row = crease.range().start.row + 1;
19229                        let nested_end_row = crease.range().end.row;
19230
19231                        if current_level < fold_at_level {
19232                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19233                        } else if current_level == fold_at_level {
19234                            // Fold iff there is no selection completely contained within the fold region
19235                            if !row_ranges_to_keep.iter().any(|selection| {
19236                                selection.end >= nested_start_row
19237                                    && selection.start <= nested_end_row
19238                            }) {
19239                                to_fold.push(crease);
19240                            }
19241                        }
19242
19243                        start_row = nested_end_row + 1;
19244                    }
19245                    None => start_row += 1,
19246                }
19247            }
19248        }
19249
19250        self.fold_creases(to_fold, true, window, cx);
19251    }
19252
19253    pub fn fold_at_level_1(
19254        &mut self,
19255        _: &actions::FoldAtLevel1,
19256        window: &mut Window,
19257        cx: &mut Context<Self>,
19258    ) {
19259        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19260    }
19261
19262    pub fn fold_at_level_2(
19263        &mut self,
19264        _: &actions::FoldAtLevel2,
19265        window: &mut Window,
19266        cx: &mut Context<Self>,
19267    ) {
19268        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19269    }
19270
19271    pub fn fold_at_level_3(
19272        &mut self,
19273        _: &actions::FoldAtLevel3,
19274        window: &mut Window,
19275        cx: &mut Context<Self>,
19276    ) {
19277        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19278    }
19279
19280    pub fn fold_at_level_4(
19281        &mut self,
19282        _: &actions::FoldAtLevel4,
19283        window: &mut Window,
19284        cx: &mut Context<Self>,
19285    ) {
19286        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19287    }
19288
19289    pub fn fold_at_level_5(
19290        &mut self,
19291        _: &actions::FoldAtLevel5,
19292        window: &mut Window,
19293        cx: &mut Context<Self>,
19294    ) {
19295        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19296    }
19297
19298    pub fn fold_at_level_6(
19299        &mut self,
19300        _: &actions::FoldAtLevel6,
19301        window: &mut Window,
19302        cx: &mut Context<Self>,
19303    ) {
19304        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19305    }
19306
19307    pub fn fold_at_level_7(
19308        &mut self,
19309        _: &actions::FoldAtLevel7,
19310        window: &mut Window,
19311        cx: &mut Context<Self>,
19312    ) {
19313        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19314    }
19315
19316    pub fn fold_at_level_8(
19317        &mut self,
19318        _: &actions::FoldAtLevel8,
19319        window: &mut Window,
19320        cx: &mut Context<Self>,
19321    ) {
19322        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19323    }
19324
19325    pub fn fold_at_level_9(
19326        &mut self,
19327        _: &actions::FoldAtLevel9,
19328        window: &mut Window,
19329        cx: &mut Context<Self>,
19330    ) {
19331        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19332    }
19333
19334    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19335        if self.buffer.read(cx).is_singleton() {
19336            let mut fold_ranges = Vec::new();
19337            let snapshot = self.buffer.read(cx).snapshot(cx);
19338
19339            for row in 0..snapshot.max_row().0 {
19340                if let Some(foldable_range) = self
19341                    .snapshot(window, cx)
19342                    .crease_for_buffer_row(MultiBufferRow(row))
19343                {
19344                    fold_ranges.push(foldable_range);
19345                }
19346            }
19347
19348            self.fold_creases(fold_ranges, true, window, cx);
19349        } else {
19350            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19351                editor
19352                    .update_in(cx, |editor, _, cx| {
19353                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19354                            editor.fold_buffer(buffer_id, cx);
19355                        }
19356                    })
19357                    .ok();
19358            });
19359        }
19360    }
19361
19362    pub fn fold_function_bodies(
19363        &mut self,
19364        _: &actions::FoldFunctionBodies,
19365        window: &mut Window,
19366        cx: &mut Context<Self>,
19367    ) {
19368        let snapshot = self.buffer.read(cx).snapshot(cx);
19369
19370        let ranges = snapshot
19371            .text_object_ranges(
19372                MultiBufferOffset(0)..snapshot.len(),
19373                TreeSitterOptions::default(),
19374            )
19375            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19376            .collect::<Vec<_>>();
19377
19378        let creases = ranges
19379            .into_iter()
19380            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19381            .collect();
19382
19383        self.fold_creases(creases, true, window, cx);
19384    }
19385
19386    pub fn fold_recursive(
19387        &mut self,
19388        _: &actions::FoldRecursive,
19389        window: &mut Window,
19390        cx: &mut Context<Self>,
19391    ) {
19392        let mut to_fold = Vec::new();
19393        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19394        let selections = self.selections.all_adjusted(&display_map);
19395
19396        for selection in selections {
19397            let range = selection.range().sorted();
19398            let buffer_start_row = range.start.row;
19399
19400            if range.start.row != range.end.row {
19401                let mut found = false;
19402                for row in range.start.row..=range.end.row {
19403                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19404                        found = true;
19405                        to_fold.push(crease);
19406                    }
19407                }
19408                if found {
19409                    continue;
19410                }
19411            }
19412
19413            for row in (0..=range.start.row).rev() {
19414                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19415                    if crease.range().end.row >= buffer_start_row {
19416                        to_fold.push(crease);
19417                    } else {
19418                        break;
19419                    }
19420                }
19421            }
19422        }
19423
19424        self.fold_creases(to_fold, true, window, cx);
19425    }
19426
19427    pub fn fold_at(
19428        &mut self,
19429        buffer_row: MultiBufferRow,
19430        window: &mut Window,
19431        cx: &mut Context<Self>,
19432    ) {
19433        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19434
19435        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19436            let autoscroll = self
19437                .selections
19438                .all::<Point>(&display_map)
19439                .iter()
19440                .any(|selection| crease.range().overlaps(&selection.range()));
19441
19442            self.fold_creases(vec![crease], autoscroll, window, cx);
19443        }
19444    }
19445
19446    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19447        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19448            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19449            let buffer = display_map.buffer_snapshot();
19450            let selections = self.selections.all::<Point>(&display_map);
19451            let ranges = selections
19452                .iter()
19453                .map(|s| {
19454                    let range = s.display_range(&display_map).sorted();
19455                    let mut start = range.start.to_point(&display_map);
19456                    let mut end = range.end.to_point(&display_map);
19457                    start.column = 0;
19458                    end.column = buffer.line_len(MultiBufferRow(end.row));
19459                    start..end
19460                })
19461                .collect::<Vec<_>>();
19462
19463            self.unfold_ranges(&ranges, true, true, cx);
19464        } else {
19465            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19466            let buffer_ids = self
19467                .selections
19468                .disjoint_anchor_ranges()
19469                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19470                .collect::<HashSet<_>>();
19471            for buffer_id in buffer_ids {
19472                self.unfold_buffer(buffer_id, cx);
19473            }
19474        }
19475    }
19476
19477    pub fn unfold_recursive(
19478        &mut self,
19479        _: &UnfoldRecursive,
19480        _window: &mut Window,
19481        cx: &mut Context<Self>,
19482    ) {
19483        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19484        let selections = self.selections.all::<Point>(&display_map);
19485        let ranges = selections
19486            .iter()
19487            .map(|s| {
19488                let mut range = s.display_range(&display_map).sorted();
19489                *range.start.column_mut() = 0;
19490                *range.end.column_mut() = display_map.line_len(range.end.row());
19491                let start = range.start.to_point(&display_map);
19492                let end = range.end.to_point(&display_map);
19493                start..end
19494            })
19495            .collect::<Vec<_>>();
19496
19497        self.unfold_ranges(&ranges, true, true, cx);
19498    }
19499
19500    pub fn unfold_at(
19501        &mut self,
19502        buffer_row: MultiBufferRow,
19503        _window: &mut Window,
19504        cx: &mut Context<Self>,
19505    ) {
19506        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19507
19508        let intersection_range = Point::new(buffer_row.0, 0)
19509            ..Point::new(
19510                buffer_row.0,
19511                display_map.buffer_snapshot().line_len(buffer_row),
19512            );
19513
19514        let autoscroll = self
19515            .selections
19516            .all::<Point>(&display_map)
19517            .iter()
19518            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19519
19520        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19521    }
19522
19523    pub fn unfold_all(
19524        &mut self,
19525        _: &actions::UnfoldAll,
19526        _window: &mut Window,
19527        cx: &mut Context<Self>,
19528    ) {
19529        if self.buffer.read(cx).is_singleton() {
19530            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19531            self.unfold_ranges(
19532                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19533                true,
19534                true,
19535                cx,
19536            );
19537        } else {
19538            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19539                editor
19540                    .update(cx, |editor, cx| {
19541                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19542                            editor.unfold_buffer(buffer_id, cx);
19543                        }
19544                    })
19545                    .ok();
19546            });
19547        }
19548    }
19549
19550    pub fn fold_selected_ranges(
19551        &mut self,
19552        _: &FoldSelectedRanges,
19553        window: &mut Window,
19554        cx: &mut Context<Self>,
19555    ) {
19556        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19557        let selections = self.selections.all_adjusted(&display_map);
19558        let ranges = selections
19559            .into_iter()
19560            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19561            .collect::<Vec<_>>();
19562        self.fold_creases(ranges, true, window, cx);
19563    }
19564
19565    pub fn fold_ranges<T: ToOffset + Clone>(
19566        &mut self,
19567        ranges: Vec<Range<T>>,
19568        auto_scroll: bool,
19569        window: &mut Window,
19570        cx: &mut Context<Self>,
19571    ) {
19572        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19573        let ranges = ranges
19574            .into_iter()
19575            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19576            .collect::<Vec<_>>();
19577        self.fold_creases(ranges, auto_scroll, window, cx);
19578    }
19579
19580    pub fn fold_creases<T: ToOffset + Clone>(
19581        &mut self,
19582        creases: Vec<Crease<T>>,
19583        auto_scroll: bool,
19584        _window: &mut Window,
19585        cx: &mut Context<Self>,
19586    ) {
19587        if creases.is_empty() {
19588            return;
19589        }
19590
19591        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19592
19593        if auto_scroll {
19594            self.request_autoscroll(Autoscroll::fit(), cx);
19595        }
19596
19597        cx.notify();
19598
19599        self.scrollbar_marker_state.dirty = true;
19600        self.folds_did_change(cx);
19601    }
19602
19603    /// Removes any folds whose ranges intersect any of the given ranges.
19604    pub fn unfold_ranges<T: ToOffset + Clone>(
19605        &mut self,
19606        ranges: &[Range<T>],
19607        inclusive: bool,
19608        auto_scroll: bool,
19609        cx: &mut Context<Self>,
19610    ) {
19611        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19612            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19613        });
19614        self.folds_did_change(cx);
19615    }
19616
19617    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19618        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19619            return;
19620        }
19621
19622        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19623        self.display_map.update(cx, |display_map, cx| {
19624            display_map.fold_buffers([buffer_id], cx)
19625        });
19626
19627        let snapshot = self.display_snapshot(cx);
19628        self.selections.change_with(&snapshot, |selections| {
19629            selections.remove_selections_from_buffer(buffer_id);
19630        });
19631
19632        cx.emit(EditorEvent::BufferFoldToggled {
19633            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19634            folded: true,
19635        });
19636        cx.notify();
19637    }
19638
19639    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19640        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19641            return;
19642        }
19643        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19644        self.display_map.update(cx, |display_map, cx| {
19645            display_map.unfold_buffers([buffer_id], cx);
19646        });
19647        cx.emit(EditorEvent::BufferFoldToggled {
19648            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19649            folded: false,
19650        });
19651        cx.notify();
19652    }
19653
19654    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19655        self.display_map.read(cx).is_buffer_folded(buffer)
19656    }
19657
19658    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19659        self.display_map.read(cx).folded_buffers()
19660    }
19661
19662    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19663        self.display_map.update(cx, |display_map, cx| {
19664            display_map.disable_header_for_buffer(buffer_id, cx);
19665        });
19666        cx.notify();
19667    }
19668
19669    /// Removes any folds with the given ranges.
19670    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19671        &mut self,
19672        ranges: &[Range<T>],
19673        type_id: TypeId,
19674        auto_scroll: bool,
19675        cx: &mut Context<Self>,
19676    ) {
19677        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19678            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19679        });
19680        self.folds_did_change(cx);
19681    }
19682
19683    fn remove_folds_with<T: ToOffset + Clone>(
19684        &mut self,
19685        ranges: &[Range<T>],
19686        auto_scroll: bool,
19687        cx: &mut Context<Self>,
19688        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19689    ) {
19690        if ranges.is_empty() {
19691            return;
19692        }
19693
19694        let mut buffers_affected = HashSet::default();
19695        let multi_buffer = self.buffer().read(cx);
19696        for range in ranges {
19697            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19698                buffers_affected.insert(buffer.read(cx).remote_id());
19699            };
19700        }
19701
19702        self.display_map.update(cx, update);
19703
19704        if auto_scroll {
19705            self.request_autoscroll(Autoscroll::fit(), cx);
19706        }
19707
19708        cx.notify();
19709        self.scrollbar_marker_state.dirty = true;
19710        self.active_indent_guides_state.dirty = true;
19711    }
19712
19713    pub fn update_renderer_widths(
19714        &mut self,
19715        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19716        cx: &mut Context<Self>,
19717    ) -> bool {
19718        self.display_map
19719            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19720    }
19721
19722    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19723        self.display_map.read(cx).fold_placeholder.clone()
19724    }
19725
19726    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19727        self.use_base_text_line_numbers = show;
19728    }
19729
19730    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19731        self.buffer.update(cx, |buffer, cx| {
19732            buffer.set_all_diff_hunks_expanded(cx);
19733        });
19734    }
19735
19736    pub fn expand_all_diff_hunks(
19737        &mut self,
19738        _: &ExpandAllDiffHunks,
19739        _window: &mut Window,
19740        cx: &mut Context<Self>,
19741    ) {
19742        self.buffer.update(cx, |buffer, cx| {
19743            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19744        });
19745    }
19746
19747    pub fn collapse_all_diff_hunks(
19748        &mut self,
19749        _: &CollapseAllDiffHunks,
19750        _window: &mut Window,
19751        cx: &mut Context<Self>,
19752    ) {
19753        self.buffer.update(cx, |buffer, cx| {
19754            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19755        });
19756    }
19757
19758    pub fn toggle_selected_diff_hunks(
19759        &mut self,
19760        _: &ToggleSelectedDiffHunks,
19761        _window: &mut Window,
19762        cx: &mut Context<Self>,
19763    ) {
19764        let ranges: Vec<_> = self
19765            .selections
19766            .disjoint_anchors()
19767            .iter()
19768            .map(|s| s.range())
19769            .collect();
19770        self.toggle_diff_hunks_in_ranges(ranges, cx);
19771    }
19772
19773    pub fn diff_hunks_in_ranges<'a>(
19774        &'a self,
19775        ranges: &'a [Range<Anchor>],
19776        buffer: &'a MultiBufferSnapshot,
19777    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19778        ranges.iter().flat_map(move |range| {
19779            let end_excerpt_id = range.end.excerpt_id;
19780            let range = range.to_point(buffer);
19781            let mut peek_end = range.end;
19782            if range.end.row < buffer.max_row().0 {
19783                peek_end = Point::new(range.end.row + 1, 0);
19784            }
19785            buffer
19786                .diff_hunks_in_range(range.start..peek_end)
19787                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19788        })
19789    }
19790
19791    pub fn has_stageable_diff_hunks_in_ranges(
19792        &self,
19793        ranges: &[Range<Anchor>],
19794        snapshot: &MultiBufferSnapshot,
19795    ) -> bool {
19796        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19797        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19798    }
19799
19800    pub fn toggle_staged_selected_diff_hunks(
19801        &mut self,
19802        _: &::git::ToggleStaged,
19803        _: &mut Window,
19804        cx: &mut Context<Self>,
19805    ) {
19806        let snapshot = self.buffer.read(cx).snapshot(cx);
19807        let ranges: Vec<_> = self
19808            .selections
19809            .disjoint_anchors()
19810            .iter()
19811            .map(|s| s.range())
19812            .collect();
19813        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19814        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19815    }
19816
19817    pub fn set_render_diff_hunk_controls(
19818        &mut self,
19819        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19820        cx: &mut Context<Self>,
19821    ) {
19822        self.render_diff_hunk_controls = render_diff_hunk_controls;
19823        cx.notify();
19824    }
19825
19826    pub fn stage_and_next(
19827        &mut self,
19828        _: &::git::StageAndNext,
19829        window: &mut Window,
19830        cx: &mut Context<Self>,
19831    ) {
19832        self.do_stage_or_unstage_and_next(true, window, cx);
19833    }
19834
19835    pub fn unstage_and_next(
19836        &mut self,
19837        _: &::git::UnstageAndNext,
19838        window: &mut Window,
19839        cx: &mut Context<Self>,
19840    ) {
19841        self.do_stage_or_unstage_and_next(false, window, cx);
19842    }
19843
19844    pub fn stage_or_unstage_diff_hunks(
19845        &mut self,
19846        stage: bool,
19847        ranges: Vec<Range<Anchor>>,
19848        cx: &mut Context<Self>,
19849    ) {
19850        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19851        cx.spawn(async move |this, cx| {
19852            task.await?;
19853            this.update(cx, |this, cx| {
19854                let snapshot = this.buffer.read(cx).snapshot(cx);
19855                let chunk_by = this
19856                    .diff_hunks_in_ranges(&ranges, &snapshot)
19857                    .chunk_by(|hunk| hunk.buffer_id);
19858                for (buffer_id, hunks) in &chunk_by {
19859                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19860                }
19861            })
19862        })
19863        .detach_and_log_err(cx);
19864    }
19865
19866    fn save_buffers_for_ranges_if_needed(
19867        &mut self,
19868        ranges: &[Range<Anchor>],
19869        cx: &mut Context<Editor>,
19870    ) -> Task<Result<()>> {
19871        let multibuffer = self.buffer.read(cx);
19872        let snapshot = multibuffer.read(cx);
19873        let buffer_ids: HashSet<_> = ranges
19874            .iter()
19875            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19876            .collect();
19877        drop(snapshot);
19878
19879        let mut buffers = HashSet::default();
19880        for buffer_id in buffer_ids {
19881            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19882                let buffer = buffer_entity.read(cx);
19883                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19884                {
19885                    buffers.insert(buffer_entity);
19886                }
19887            }
19888        }
19889
19890        if let Some(project) = &self.project {
19891            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19892        } else {
19893            Task::ready(Ok(()))
19894        }
19895    }
19896
19897    fn do_stage_or_unstage_and_next(
19898        &mut self,
19899        stage: bool,
19900        window: &mut Window,
19901        cx: &mut Context<Self>,
19902    ) {
19903        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19904
19905        if ranges.iter().any(|range| range.start != range.end) {
19906            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19907            return;
19908        }
19909
19910        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19911        let snapshot = self.snapshot(window, cx);
19912        let position = self
19913            .selections
19914            .newest::<Point>(&snapshot.display_snapshot)
19915            .head();
19916        let mut row = snapshot
19917            .buffer_snapshot()
19918            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19919            .find(|hunk| hunk.row_range.start.0 > position.row)
19920            .map(|hunk| hunk.row_range.start);
19921
19922        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19923        // Outside of the project diff editor, wrap around to the beginning.
19924        if !all_diff_hunks_expanded {
19925            row = row.or_else(|| {
19926                snapshot
19927                    .buffer_snapshot()
19928                    .diff_hunks_in_range(Point::zero()..position)
19929                    .find(|hunk| hunk.row_range.end.0 < position.row)
19930                    .map(|hunk| hunk.row_range.start)
19931            });
19932        }
19933
19934        if let Some(row) = row {
19935            let destination = Point::new(row.0, 0);
19936            let autoscroll = Autoscroll::center();
19937
19938            self.unfold_ranges(&[destination..destination], false, false, cx);
19939            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19940                s.select_ranges([destination..destination]);
19941            });
19942        }
19943    }
19944
19945    fn do_stage_or_unstage(
19946        &self,
19947        stage: bool,
19948        buffer_id: BufferId,
19949        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19950        cx: &mut App,
19951    ) -> Option<()> {
19952        let project = self.project()?;
19953        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19954        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19955        let buffer_snapshot = buffer.read(cx).snapshot();
19956        let file_exists = buffer_snapshot
19957            .file()
19958            .is_some_and(|file| file.disk_state().exists());
19959        diff.update(cx, |diff, cx| {
19960            diff.stage_or_unstage_hunks(
19961                stage,
19962                &hunks
19963                    .map(|hunk| buffer_diff::DiffHunk {
19964                        buffer_range: hunk.buffer_range,
19965                        // We don't need to pass in word diffs here because they're only used for rendering and
19966                        // this function changes internal state
19967                        base_word_diffs: Vec::default(),
19968                        buffer_word_diffs: Vec::default(),
19969                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19970                            ..hunk.diff_base_byte_range.end.0,
19971                        secondary_status: hunk.secondary_status,
19972                        range: Point::zero()..Point::zero(), // unused
19973                    })
19974                    .collect::<Vec<_>>(),
19975                &buffer_snapshot,
19976                file_exists,
19977                cx,
19978            )
19979        });
19980        None
19981    }
19982
19983    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19984        let ranges: Vec<_> = self
19985            .selections
19986            .disjoint_anchors()
19987            .iter()
19988            .map(|s| s.range())
19989            .collect();
19990        self.buffer
19991            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19992    }
19993
19994    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19995        self.buffer.update(cx, |buffer, cx| {
19996            let ranges = vec![Anchor::min()..Anchor::max()];
19997            if !buffer.all_diff_hunks_expanded()
19998                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19999            {
20000                buffer.collapse_diff_hunks(ranges, cx);
20001                true
20002            } else {
20003                false
20004            }
20005        })
20006    }
20007
20008    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
20009        if self.buffer.read(cx).all_diff_hunks_expanded() {
20010            return true;
20011        }
20012        let ranges = vec![Anchor::min()..Anchor::max()];
20013        self.buffer
20014            .read(cx)
20015            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
20016    }
20017
20018    fn toggle_diff_hunks_in_ranges(
20019        &mut self,
20020        ranges: Vec<Range<Anchor>>,
20021        cx: &mut Context<Editor>,
20022    ) {
20023        self.buffer.update(cx, |buffer, cx| {
20024            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
20025            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
20026        })
20027    }
20028
20029    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20030        self.buffer.update(cx, |buffer, cx| {
20031            let snapshot = buffer.snapshot(cx);
20032            let excerpt_id = range.end.excerpt_id;
20033            let point_range = range.to_point(&snapshot);
20034            let expand = !buffer.single_hunk_is_expanded(range, cx);
20035            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
20036        })
20037    }
20038
20039    pub(crate) fn apply_all_diff_hunks(
20040        &mut self,
20041        _: &ApplyAllDiffHunks,
20042        window: &mut Window,
20043        cx: &mut Context<Self>,
20044    ) {
20045        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20046
20047        let buffers = self.buffer.read(cx).all_buffers();
20048        for branch_buffer in buffers {
20049            branch_buffer.update(cx, |branch_buffer, cx| {
20050                branch_buffer.merge_into_base(Vec::new(), cx);
20051            });
20052        }
20053
20054        if let Some(project) = self.project.clone() {
20055            self.save(
20056                SaveOptions {
20057                    format: true,
20058                    autosave: false,
20059                },
20060                project,
20061                window,
20062                cx,
20063            )
20064            .detach_and_log_err(cx);
20065        }
20066    }
20067
20068    pub(crate) fn apply_selected_diff_hunks(
20069        &mut self,
20070        _: &ApplyDiffHunk,
20071        window: &mut Window,
20072        cx: &mut Context<Self>,
20073    ) {
20074        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20075        let snapshot = self.snapshot(window, cx);
20076        let hunks = snapshot.hunks_for_ranges(
20077            self.selections
20078                .all(&snapshot.display_snapshot)
20079                .into_iter()
20080                .map(|selection| selection.range()),
20081        );
20082        let mut ranges_by_buffer = HashMap::default();
20083        self.transact(window, cx, |editor, _window, cx| {
20084            for hunk in hunks {
20085                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20086                    ranges_by_buffer
20087                        .entry(buffer.clone())
20088                        .or_insert_with(Vec::new)
20089                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20090                }
20091            }
20092
20093            for (buffer, ranges) in ranges_by_buffer {
20094                buffer.update(cx, |buffer, cx| {
20095                    buffer.merge_into_base(ranges, cx);
20096                });
20097            }
20098        });
20099
20100        if let Some(project) = self.project.clone() {
20101            self.save(
20102                SaveOptions {
20103                    format: true,
20104                    autosave: false,
20105                },
20106                project,
20107                window,
20108                cx,
20109            )
20110            .detach_and_log_err(cx);
20111        }
20112    }
20113
20114    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20115        if hovered != self.gutter_hovered {
20116            self.gutter_hovered = hovered;
20117            cx.notify();
20118        }
20119    }
20120
20121    pub fn insert_blocks(
20122        &mut self,
20123        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20124        autoscroll: Option<Autoscroll>,
20125        cx: &mut Context<Self>,
20126    ) -> Vec<CustomBlockId> {
20127        let blocks = self
20128            .display_map
20129            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20130        if let Some(autoscroll) = autoscroll {
20131            self.request_autoscroll(autoscroll, cx);
20132        }
20133        cx.notify();
20134        blocks
20135    }
20136
20137    pub fn resize_blocks(
20138        &mut self,
20139        heights: HashMap<CustomBlockId, u32>,
20140        autoscroll: Option<Autoscroll>,
20141        cx: &mut Context<Self>,
20142    ) {
20143        self.display_map
20144            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20145        if let Some(autoscroll) = autoscroll {
20146            self.request_autoscroll(autoscroll, cx);
20147        }
20148        cx.notify();
20149    }
20150
20151    pub fn replace_blocks(
20152        &mut self,
20153        renderers: HashMap<CustomBlockId, RenderBlock>,
20154        autoscroll: Option<Autoscroll>,
20155        cx: &mut Context<Self>,
20156    ) {
20157        self.display_map
20158            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20159        if let Some(autoscroll) = autoscroll {
20160            self.request_autoscroll(autoscroll, cx);
20161        }
20162        cx.notify();
20163    }
20164
20165    pub fn remove_blocks(
20166        &mut self,
20167        block_ids: HashSet<CustomBlockId>,
20168        autoscroll: Option<Autoscroll>,
20169        cx: &mut Context<Self>,
20170    ) {
20171        self.display_map.update(cx, |display_map, cx| {
20172            display_map.remove_blocks(block_ids, cx)
20173        });
20174        if let Some(autoscroll) = autoscroll {
20175            self.request_autoscroll(autoscroll, cx);
20176        }
20177        cx.notify();
20178    }
20179
20180    pub fn row_for_block(
20181        &self,
20182        block_id: CustomBlockId,
20183        cx: &mut Context<Self>,
20184    ) -> Option<DisplayRow> {
20185        self.display_map
20186            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20187    }
20188
20189    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20190        self.focused_block = Some(focused_block);
20191    }
20192
20193    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20194        self.focused_block.take()
20195    }
20196
20197    pub fn insert_creases(
20198        &mut self,
20199        creases: impl IntoIterator<Item = Crease<Anchor>>,
20200        cx: &mut Context<Self>,
20201    ) -> Vec<CreaseId> {
20202        self.display_map
20203            .update(cx, |map, cx| map.insert_creases(creases, cx))
20204    }
20205
20206    pub fn remove_creases(
20207        &mut self,
20208        ids: impl IntoIterator<Item = CreaseId>,
20209        cx: &mut Context<Self>,
20210    ) -> Vec<(CreaseId, Range<Anchor>)> {
20211        self.display_map
20212            .update(cx, |map, cx| map.remove_creases(ids, cx))
20213    }
20214
20215    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20216        self.display_map
20217            .update(cx, |map, cx| map.snapshot(cx))
20218            .longest_row()
20219    }
20220
20221    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20222        self.display_map
20223            .update(cx, |map, cx| map.snapshot(cx))
20224            .max_point()
20225    }
20226
20227    pub fn text(&self, cx: &App) -> String {
20228        self.buffer.read(cx).read(cx).text()
20229    }
20230
20231    pub fn is_empty(&self, cx: &App) -> bool {
20232        self.buffer.read(cx).read(cx).is_empty()
20233    }
20234
20235    pub fn text_option(&self, cx: &App) -> Option<String> {
20236        let text = self.text(cx);
20237        let text = text.trim();
20238
20239        if text.is_empty() {
20240            return None;
20241        }
20242
20243        Some(text.to_string())
20244    }
20245
20246    pub fn set_text(
20247        &mut self,
20248        text: impl Into<Arc<str>>,
20249        window: &mut Window,
20250        cx: &mut Context<Self>,
20251    ) {
20252        self.transact(window, cx, |this, _, cx| {
20253            this.buffer
20254                .read(cx)
20255                .as_singleton()
20256                .expect("you can only call set_text on editors for singleton buffers")
20257                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20258        });
20259    }
20260
20261    pub fn display_text(&self, cx: &mut App) -> String {
20262        self.display_map
20263            .update(cx, |map, cx| map.snapshot(cx))
20264            .text()
20265    }
20266
20267    fn create_minimap(
20268        &self,
20269        minimap_settings: MinimapSettings,
20270        window: &mut Window,
20271        cx: &mut Context<Self>,
20272    ) -> Option<Entity<Self>> {
20273        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20274            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20275    }
20276
20277    fn initialize_new_minimap(
20278        &self,
20279        minimap_settings: MinimapSettings,
20280        window: &mut Window,
20281        cx: &mut Context<Self>,
20282    ) -> Entity<Self> {
20283        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20284
20285        let mut minimap = Editor::new_internal(
20286            EditorMode::Minimap {
20287                parent: cx.weak_entity(),
20288            },
20289            self.buffer.clone(),
20290            None,
20291            Some(self.display_map.clone()),
20292            window,
20293            cx,
20294        );
20295        minimap.scroll_manager.clone_state(&self.scroll_manager);
20296        minimap.set_text_style_refinement(TextStyleRefinement {
20297            font_size: Some(MINIMAP_FONT_SIZE),
20298            font_weight: Some(MINIMAP_FONT_WEIGHT),
20299            ..Default::default()
20300        });
20301        minimap.update_minimap_configuration(minimap_settings, cx);
20302        cx.new(|_| minimap)
20303    }
20304
20305    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20306        let current_line_highlight = minimap_settings
20307            .current_line_highlight
20308            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20309        self.set_current_line_highlight(Some(current_line_highlight));
20310    }
20311
20312    pub fn minimap(&self) -> Option<&Entity<Self>> {
20313        self.minimap
20314            .as_ref()
20315            .filter(|_| self.minimap_visibility.visible())
20316    }
20317
20318    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20319        let mut wrap_guides = smallvec![];
20320
20321        if self.show_wrap_guides == Some(false) {
20322            return wrap_guides;
20323        }
20324
20325        let settings = self.buffer.read(cx).language_settings(cx);
20326        if settings.show_wrap_guides {
20327            match self.soft_wrap_mode(cx) {
20328                SoftWrap::Column(soft_wrap) => {
20329                    wrap_guides.push((soft_wrap as usize, true));
20330                }
20331                SoftWrap::Bounded(soft_wrap) => {
20332                    wrap_guides.push((soft_wrap as usize, true));
20333                }
20334                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20335            }
20336            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20337        }
20338
20339        wrap_guides
20340    }
20341
20342    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20343        let settings = self.buffer.read(cx).language_settings(cx);
20344        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20345        match mode {
20346            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20347                SoftWrap::None
20348            }
20349            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20350            language_settings::SoftWrap::PreferredLineLength => {
20351                SoftWrap::Column(settings.preferred_line_length)
20352            }
20353            language_settings::SoftWrap::Bounded => {
20354                SoftWrap::Bounded(settings.preferred_line_length)
20355            }
20356        }
20357    }
20358
20359    pub fn set_soft_wrap_mode(
20360        &mut self,
20361        mode: language_settings::SoftWrap,
20362
20363        cx: &mut Context<Self>,
20364    ) {
20365        self.soft_wrap_mode_override = Some(mode);
20366        cx.notify();
20367    }
20368
20369    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20370        self.hard_wrap = hard_wrap;
20371        cx.notify();
20372    }
20373
20374    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20375        self.text_style_refinement = Some(style);
20376    }
20377
20378    /// called by the Element so we know what style we were most recently rendered with.
20379    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20380        // We intentionally do not inform the display map about the minimap style
20381        // so that wrapping is not recalculated and stays consistent for the editor
20382        // and its linked minimap.
20383        if !self.mode.is_minimap() {
20384            let font = style.text.font();
20385            let font_size = style.text.font_size.to_pixels(window.rem_size());
20386            let display_map = self
20387                .placeholder_display_map
20388                .as_ref()
20389                .filter(|_| self.is_empty(cx))
20390                .unwrap_or(&self.display_map);
20391
20392            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20393        }
20394        self.style = Some(style);
20395    }
20396
20397    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20398        if self.style.is_none() {
20399            self.style = Some(self.create_style(cx));
20400        }
20401        self.style.as_ref().unwrap()
20402    }
20403
20404    // Called by the element. This method is not designed to be called outside of the editor
20405    // element's layout code because it does not notify when rewrapping is computed synchronously.
20406    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20407        if self.is_empty(cx) {
20408            self.placeholder_display_map
20409                .as_ref()
20410                .map_or(false, |display_map| {
20411                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20412                })
20413        } else {
20414            self.display_map
20415                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20416        }
20417    }
20418
20419    pub fn set_soft_wrap(&mut self) {
20420        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20421    }
20422
20423    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20424        if self.soft_wrap_mode_override.is_some() {
20425            self.soft_wrap_mode_override.take();
20426        } else {
20427            let soft_wrap = match self.soft_wrap_mode(cx) {
20428                SoftWrap::GitDiff => return,
20429                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20430                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20431                    language_settings::SoftWrap::None
20432                }
20433            };
20434            self.soft_wrap_mode_override = Some(soft_wrap);
20435        }
20436        cx.notify();
20437    }
20438
20439    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20440        let Some(workspace) = self.workspace() else {
20441            return;
20442        };
20443        let fs = workspace.read(cx).app_state().fs.clone();
20444        let current_show = TabBarSettings::get_global(cx).show;
20445        update_settings_file(fs, cx, move |setting, _| {
20446            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20447        });
20448    }
20449
20450    pub fn toggle_indent_guides(
20451        &mut self,
20452        _: &ToggleIndentGuides,
20453        _: &mut Window,
20454        cx: &mut Context<Self>,
20455    ) {
20456        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20457            self.buffer
20458                .read(cx)
20459                .language_settings(cx)
20460                .indent_guides
20461                .enabled
20462        });
20463        self.show_indent_guides = Some(!currently_enabled);
20464        cx.notify();
20465    }
20466
20467    fn should_show_indent_guides(&self) -> Option<bool> {
20468        self.show_indent_guides
20469    }
20470
20471    pub fn disable_indent_guides_for_buffer(
20472        &mut self,
20473        buffer_id: BufferId,
20474        cx: &mut Context<Self>,
20475    ) {
20476        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20477        cx.notify();
20478    }
20479
20480    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20481        self.buffers_with_disabled_indent_guides
20482            .contains(&buffer_id)
20483    }
20484
20485    pub fn toggle_line_numbers(
20486        &mut self,
20487        _: &ToggleLineNumbers,
20488        _: &mut Window,
20489        cx: &mut Context<Self>,
20490    ) {
20491        let mut editor_settings = EditorSettings::get_global(cx).clone();
20492        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20493        EditorSettings::override_global(editor_settings, cx);
20494    }
20495
20496    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20497        if let Some(show_line_numbers) = self.show_line_numbers {
20498            return show_line_numbers;
20499        }
20500        EditorSettings::get_global(cx).gutter.line_numbers
20501    }
20502
20503    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
20504        match (
20505            self.use_relative_line_numbers,
20506            EditorSettings::get_global(cx).relative_line_numbers,
20507        ) {
20508            (None, setting) => setting,
20509            (Some(false), _) => RelativeLineNumbers::Disabled,
20510            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20511            (Some(true), _) => RelativeLineNumbers::Enabled,
20512        }
20513    }
20514
20515    pub fn toggle_relative_line_numbers(
20516        &mut self,
20517        _: &ToggleRelativeLineNumbers,
20518        _: &mut Window,
20519        cx: &mut Context<Self>,
20520    ) {
20521        let is_relative = self.relative_line_numbers(cx);
20522        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20523    }
20524
20525    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20526        self.use_relative_line_numbers = is_relative;
20527        cx.notify();
20528    }
20529
20530    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20531        self.show_gutter = show_gutter;
20532        cx.notify();
20533    }
20534
20535    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20536        self.show_scrollbars = ScrollbarAxes {
20537            horizontal: show,
20538            vertical: show,
20539        };
20540        cx.notify();
20541    }
20542
20543    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20544        self.show_scrollbars.vertical = show;
20545        cx.notify();
20546    }
20547
20548    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20549        self.show_scrollbars.horizontal = show;
20550        cx.notify();
20551    }
20552
20553    pub fn set_minimap_visibility(
20554        &mut self,
20555        minimap_visibility: MinimapVisibility,
20556        window: &mut Window,
20557        cx: &mut Context<Self>,
20558    ) {
20559        if self.minimap_visibility != minimap_visibility {
20560            if minimap_visibility.visible() && self.minimap.is_none() {
20561                let minimap_settings = EditorSettings::get_global(cx).minimap;
20562                self.minimap =
20563                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20564            }
20565            self.minimap_visibility = minimap_visibility;
20566            cx.notify();
20567        }
20568    }
20569
20570    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20571        self.set_show_scrollbars(false, cx);
20572        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20573    }
20574
20575    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20576        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20577    }
20578
20579    /// Normally the text in full mode and auto height editors is padded on the
20580    /// left side by roughly half a character width for improved hit testing.
20581    ///
20582    /// Use this method to disable this for cases where this is not wanted (e.g.
20583    /// if you want to align the editor text with some other text above or below)
20584    /// or if you want to add this padding to single-line editors.
20585    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20586        self.offset_content = offset_content;
20587        cx.notify();
20588    }
20589
20590    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20591        self.show_line_numbers = Some(show_line_numbers);
20592        cx.notify();
20593    }
20594
20595    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20596        self.disable_expand_excerpt_buttons = true;
20597        cx.notify();
20598    }
20599
20600    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20601        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20602        cx.notify();
20603    }
20604
20605    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20606        self.show_code_actions = Some(show_code_actions);
20607        cx.notify();
20608    }
20609
20610    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20611        self.show_runnables = Some(show_runnables);
20612        cx.notify();
20613    }
20614
20615    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20616        self.show_breakpoints = Some(show_breakpoints);
20617        cx.notify();
20618    }
20619
20620    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20621        if self.display_map.read(cx).masked != masked {
20622            self.display_map.update(cx, |map, _| map.masked = masked);
20623        }
20624        cx.notify()
20625    }
20626
20627    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20628        self.show_wrap_guides = Some(show_wrap_guides);
20629        cx.notify();
20630    }
20631
20632    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20633        self.show_indent_guides = Some(show_indent_guides);
20634        cx.notify();
20635    }
20636
20637    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20638        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20639            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20640                && let Some(dir) = file.abs_path(cx).parent()
20641            {
20642                return Some(dir.to_owned());
20643            }
20644        }
20645
20646        None
20647    }
20648
20649    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20650        self.active_excerpt(cx)?
20651            .1
20652            .read(cx)
20653            .file()
20654            .and_then(|f| f.as_local())
20655    }
20656
20657    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20658        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20659            let buffer = buffer.read(cx);
20660            if let Some(project_path) = buffer.project_path(cx) {
20661                let project = self.project()?.read(cx);
20662                project.absolute_path(&project_path, cx)
20663            } else {
20664                buffer
20665                    .file()
20666                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20667            }
20668        })
20669    }
20670
20671    pub fn reveal_in_finder(
20672        &mut self,
20673        _: &RevealInFileManager,
20674        _window: &mut Window,
20675        cx: &mut Context<Self>,
20676    ) {
20677        if let Some(target) = self.target_file(cx) {
20678            cx.reveal_path(&target.abs_path(cx));
20679        }
20680    }
20681
20682    pub fn copy_path(
20683        &mut self,
20684        _: &zed_actions::workspace::CopyPath,
20685        _window: &mut Window,
20686        cx: &mut Context<Self>,
20687    ) {
20688        if let Some(path) = self.target_file_abs_path(cx)
20689            && let Some(path) = path.to_str()
20690        {
20691            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20692        } else {
20693            cx.propagate();
20694        }
20695    }
20696
20697    pub fn copy_relative_path(
20698        &mut self,
20699        _: &zed_actions::workspace::CopyRelativePath,
20700        _window: &mut Window,
20701        cx: &mut Context<Self>,
20702    ) {
20703        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20704            let project = self.project()?.read(cx);
20705            let path = buffer.read(cx).file()?.path();
20706            let path = path.display(project.path_style(cx));
20707            Some(path)
20708        }) {
20709            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20710        } else {
20711            cx.propagate();
20712        }
20713    }
20714
20715    /// Returns the project path for the editor's buffer, if any buffer is
20716    /// opened in the editor.
20717    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20718        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20719            buffer.read(cx).project_path(cx)
20720        } else {
20721            None
20722        }
20723    }
20724
20725    // Returns true if the editor handled a go-to-line request
20726    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20727        maybe!({
20728            let breakpoint_store = self.breakpoint_store.as_ref()?;
20729
20730            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20731            else {
20732                self.clear_row_highlights::<ActiveDebugLine>();
20733                return None;
20734            };
20735
20736            let position = active_stack_frame.position;
20737            let buffer_id = position.buffer_id?;
20738            let snapshot = self
20739                .project
20740                .as_ref()?
20741                .read(cx)
20742                .buffer_for_id(buffer_id, cx)?
20743                .read(cx)
20744                .snapshot();
20745
20746            let mut handled = false;
20747            for (id, ExcerptRange { context, .. }) in
20748                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20749            {
20750                if context.start.cmp(&position, &snapshot).is_ge()
20751                    || context.end.cmp(&position, &snapshot).is_lt()
20752                {
20753                    continue;
20754                }
20755                let snapshot = self.buffer.read(cx).snapshot(cx);
20756                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20757
20758                handled = true;
20759                self.clear_row_highlights::<ActiveDebugLine>();
20760
20761                self.go_to_line::<ActiveDebugLine>(
20762                    multibuffer_anchor,
20763                    Some(cx.theme().colors().editor_debugger_active_line_background),
20764                    window,
20765                    cx,
20766                );
20767
20768                cx.notify();
20769            }
20770
20771            handled.then_some(())
20772        })
20773        .is_some()
20774    }
20775
20776    pub fn copy_file_name_without_extension(
20777        &mut self,
20778        _: &CopyFileNameWithoutExtension,
20779        _: &mut Window,
20780        cx: &mut Context<Self>,
20781    ) {
20782        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20783            let file = buffer.read(cx).file()?;
20784            file.path().file_stem()
20785        }) {
20786            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20787        }
20788    }
20789
20790    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20791        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20792            let file = buffer.read(cx).file()?;
20793            Some(file.file_name(cx))
20794        }) {
20795            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20796        }
20797    }
20798
20799    pub fn toggle_git_blame(
20800        &mut self,
20801        _: &::git::Blame,
20802        window: &mut Window,
20803        cx: &mut Context<Self>,
20804    ) {
20805        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20806
20807        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20808            self.start_git_blame(true, window, cx);
20809        }
20810
20811        cx.notify();
20812    }
20813
20814    pub fn toggle_git_blame_inline(
20815        &mut self,
20816        _: &ToggleGitBlameInline,
20817        window: &mut Window,
20818        cx: &mut Context<Self>,
20819    ) {
20820        self.toggle_git_blame_inline_internal(true, window, cx);
20821        cx.notify();
20822    }
20823
20824    pub fn open_git_blame_commit(
20825        &mut self,
20826        _: &OpenGitBlameCommit,
20827        window: &mut Window,
20828        cx: &mut Context<Self>,
20829    ) {
20830        self.open_git_blame_commit_internal(window, cx);
20831    }
20832
20833    fn open_git_blame_commit_internal(
20834        &mut self,
20835        window: &mut Window,
20836        cx: &mut Context<Self>,
20837    ) -> Option<()> {
20838        let blame = self.blame.as_ref()?;
20839        let snapshot = self.snapshot(window, cx);
20840        let cursor = self
20841            .selections
20842            .newest::<Point>(&snapshot.display_snapshot)
20843            .head();
20844        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20845        let (_, blame_entry) = blame
20846            .update(cx, |blame, cx| {
20847                blame
20848                    .blame_for_rows(
20849                        &[RowInfo {
20850                            buffer_id: Some(buffer.remote_id()),
20851                            buffer_row: Some(point.row),
20852                            ..Default::default()
20853                        }],
20854                        cx,
20855                    )
20856                    .next()
20857            })
20858            .flatten()?;
20859        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20860        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20861        let workspace = self.workspace()?.downgrade();
20862        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20863        None
20864    }
20865
20866    pub fn git_blame_inline_enabled(&self) -> bool {
20867        self.git_blame_inline_enabled
20868    }
20869
20870    pub fn toggle_selection_menu(
20871        &mut self,
20872        _: &ToggleSelectionMenu,
20873        _: &mut Window,
20874        cx: &mut Context<Self>,
20875    ) {
20876        self.show_selection_menu = self
20877            .show_selection_menu
20878            .map(|show_selections_menu| !show_selections_menu)
20879            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20880
20881        cx.notify();
20882    }
20883
20884    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20885        self.show_selection_menu
20886            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20887    }
20888
20889    fn start_git_blame(
20890        &mut self,
20891        user_triggered: bool,
20892        window: &mut Window,
20893        cx: &mut Context<Self>,
20894    ) {
20895        if let Some(project) = self.project() {
20896            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20897                && buffer.read(cx).file().is_none()
20898            {
20899                return;
20900            }
20901
20902            let focused = self.focus_handle(cx).contains_focused(window, cx);
20903
20904            let project = project.clone();
20905            let blame = cx
20906                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20907            self.blame_subscription =
20908                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20909            self.blame = Some(blame);
20910        }
20911    }
20912
20913    fn toggle_git_blame_inline_internal(
20914        &mut self,
20915        user_triggered: bool,
20916        window: &mut Window,
20917        cx: &mut Context<Self>,
20918    ) {
20919        if self.git_blame_inline_enabled {
20920            self.git_blame_inline_enabled = false;
20921            self.show_git_blame_inline = false;
20922            self.show_git_blame_inline_delay_task.take();
20923        } else {
20924            self.git_blame_inline_enabled = true;
20925            self.start_git_blame_inline(user_triggered, window, cx);
20926        }
20927
20928        cx.notify();
20929    }
20930
20931    fn start_git_blame_inline(
20932        &mut self,
20933        user_triggered: bool,
20934        window: &mut Window,
20935        cx: &mut Context<Self>,
20936    ) {
20937        self.start_git_blame(user_triggered, window, cx);
20938
20939        if ProjectSettings::get_global(cx)
20940            .git
20941            .inline_blame_delay()
20942            .is_some()
20943        {
20944            self.start_inline_blame_timer(window, cx);
20945        } else {
20946            self.show_git_blame_inline = true
20947        }
20948    }
20949
20950    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20951        self.blame.as_ref()
20952    }
20953
20954    pub fn show_git_blame_gutter(&self) -> bool {
20955        self.show_git_blame_gutter
20956    }
20957
20958    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20959        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20960    }
20961
20962    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20963        self.show_git_blame_inline
20964            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20965            && !self.newest_selection_head_on_empty_line(cx)
20966            && self.has_blame_entries(cx)
20967    }
20968
20969    fn has_blame_entries(&self, cx: &App) -> bool {
20970        self.blame()
20971            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20972    }
20973
20974    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20975        let cursor_anchor = self.selections.newest_anchor().head();
20976
20977        let snapshot = self.buffer.read(cx).snapshot(cx);
20978        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20979
20980        snapshot.line_len(buffer_row) == 0
20981    }
20982
20983    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20984        let buffer_and_selection = maybe!({
20985            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20986            let selection_range = selection.range();
20987
20988            let multi_buffer = self.buffer().read(cx);
20989            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20990            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20991
20992            let (buffer, range, _) = if selection.reversed {
20993                buffer_ranges.first()
20994            } else {
20995                buffer_ranges.last()
20996            }?;
20997
20998            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
20999            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
21000
21001            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
21002                let selection = start_row_in_buffer..end_row_in_buffer;
21003
21004                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
21005            };
21006
21007            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
21008
21009            Some((
21010                multi_buffer.buffer(buffer.remote_id()).unwrap(),
21011                buffer_diff_snapshot.row_to_base_text_row(start_row_in_buffer, buffer)
21012                    ..buffer_diff_snapshot.row_to_base_text_row(end_row_in_buffer, buffer),
21013            ))
21014        });
21015
21016        let Some((buffer, selection)) = buffer_and_selection else {
21017            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
21018        };
21019
21020        let Some(project) = self.project() else {
21021            return Task::ready(Err(anyhow!("editor does not have project")));
21022        };
21023
21024        project.update(cx, |project, cx| {
21025            project.get_permalink_to_line(&buffer, selection, cx)
21026        })
21027    }
21028
21029    pub fn copy_permalink_to_line(
21030        &mut self,
21031        _: &CopyPermalinkToLine,
21032        window: &mut Window,
21033        cx: &mut Context<Self>,
21034    ) {
21035        let permalink_task = self.get_permalink_to_line(cx);
21036        let workspace = self.workspace();
21037
21038        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21039            Ok(permalink) => {
21040                cx.update(|_, cx| {
21041                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
21042                })
21043                .ok();
21044            }
21045            Err(err) => {
21046                let message = format!("Failed to copy permalink: {err}");
21047
21048                anyhow::Result::<()>::Err(err).log_err();
21049
21050                if let Some(workspace) = workspace {
21051                    workspace
21052                        .update_in(cx, |workspace, _, cx| {
21053                            struct CopyPermalinkToLine;
21054
21055                            workspace.show_toast(
21056                                Toast::new(
21057                                    NotificationId::unique::<CopyPermalinkToLine>(),
21058                                    message,
21059                                ),
21060                                cx,
21061                            )
21062                        })
21063                        .ok();
21064                }
21065            }
21066        })
21067        .detach();
21068    }
21069
21070    pub fn copy_file_location(
21071        &mut self,
21072        _: &CopyFileLocation,
21073        _: &mut Window,
21074        cx: &mut Context<Self>,
21075    ) {
21076        let selection = self
21077            .selections
21078            .newest::<Point>(&self.display_snapshot(cx))
21079            .start
21080            .row
21081            + 1;
21082        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21083            let project = self.project()?.read(cx);
21084            let file = buffer.read(cx).file()?;
21085            let path = file.path().display(project.path_style(cx));
21086
21087            Some(format!("{path}:{selection}"))
21088        }) {
21089            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
21090        }
21091    }
21092
21093    pub fn open_permalink_to_line(
21094        &mut self,
21095        _: &OpenPermalinkToLine,
21096        window: &mut Window,
21097        cx: &mut Context<Self>,
21098    ) {
21099        let permalink_task = self.get_permalink_to_line(cx);
21100        let workspace = self.workspace();
21101
21102        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21103            Ok(permalink) => {
21104                cx.update(|_, cx| {
21105                    cx.open_url(permalink.as_ref());
21106                })
21107                .ok();
21108            }
21109            Err(err) => {
21110                let message = format!("Failed to open permalink: {err}");
21111
21112                anyhow::Result::<()>::Err(err).log_err();
21113
21114                if let Some(workspace) = workspace {
21115                    workspace
21116                        .update(cx, |workspace, cx| {
21117                            struct OpenPermalinkToLine;
21118
21119                            workspace.show_toast(
21120                                Toast::new(
21121                                    NotificationId::unique::<OpenPermalinkToLine>(),
21122                                    message,
21123                                ),
21124                                cx,
21125                            )
21126                        })
21127                        .ok();
21128                }
21129            }
21130        })
21131        .detach();
21132    }
21133
21134    pub fn insert_uuid_v4(
21135        &mut self,
21136        _: &InsertUuidV4,
21137        window: &mut Window,
21138        cx: &mut Context<Self>,
21139    ) {
21140        self.insert_uuid(UuidVersion::V4, window, cx);
21141    }
21142
21143    pub fn insert_uuid_v7(
21144        &mut self,
21145        _: &InsertUuidV7,
21146        window: &mut Window,
21147        cx: &mut Context<Self>,
21148    ) {
21149        self.insert_uuid(UuidVersion::V7, window, cx);
21150    }
21151
21152    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
21153        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21154        self.transact(window, cx, |this, window, cx| {
21155            let edits = this
21156                .selections
21157                .all::<Point>(&this.display_snapshot(cx))
21158                .into_iter()
21159                .map(|selection| {
21160                    let uuid = match version {
21161                        UuidVersion::V4 => uuid::Uuid::new_v4(),
21162                        UuidVersion::V7 => uuid::Uuid::now_v7(),
21163                    };
21164
21165                    (selection.range(), uuid.to_string())
21166                });
21167            this.edit(edits, cx);
21168            this.refresh_edit_prediction(true, false, window, cx);
21169        });
21170    }
21171
21172    pub fn open_selections_in_multibuffer(
21173        &mut self,
21174        _: &OpenSelectionsInMultibuffer,
21175        window: &mut Window,
21176        cx: &mut Context<Self>,
21177    ) {
21178        let multibuffer = self.buffer.read(cx);
21179
21180        let Some(buffer) = multibuffer.as_singleton() else {
21181            return;
21182        };
21183
21184        let Some(workspace) = self.workspace() else {
21185            return;
21186        };
21187
21188        let title = multibuffer.title(cx).to_string();
21189
21190        let locations = self
21191            .selections
21192            .all_anchors(&self.display_snapshot(cx))
21193            .iter()
21194            .map(|selection| {
21195                (
21196                    buffer.clone(),
21197                    (selection.start.text_anchor..selection.end.text_anchor)
21198                        .to_point(buffer.read(cx)),
21199                )
21200            })
21201            .into_group_map();
21202
21203        cx.spawn_in(window, async move |_, cx| {
21204            workspace.update_in(cx, |workspace, window, cx| {
21205                Self::open_locations_in_multibuffer(
21206                    workspace,
21207                    locations,
21208                    format!("Selections for '{title}'"),
21209                    false,
21210                    false,
21211                    MultibufferSelectionMode::All,
21212                    window,
21213                    cx,
21214                );
21215            })
21216        })
21217        .detach();
21218    }
21219
21220    /// Adds a row highlight for the given range. If a row has multiple highlights, the
21221    /// last highlight added will be used.
21222    ///
21223    /// If the range ends at the beginning of a line, then that line will not be highlighted.
21224    pub fn highlight_rows<T: 'static>(
21225        &mut self,
21226        range: Range<Anchor>,
21227        color: Hsla,
21228        options: RowHighlightOptions,
21229        cx: &mut Context<Self>,
21230    ) {
21231        let snapshot = self.buffer().read(cx).snapshot(cx);
21232        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21233        let ix = row_highlights.binary_search_by(|highlight| {
21234            Ordering::Equal
21235                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
21236                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
21237        });
21238
21239        if let Err(mut ix) = ix {
21240            let index = post_inc(&mut self.highlight_order);
21241
21242            // If this range intersects with the preceding highlight, then merge it with
21243            // the preceding highlight. Otherwise insert a new highlight.
21244            let mut merged = false;
21245            if ix > 0 {
21246                let prev_highlight = &mut row_highlights[ix - 1];
21247                if prev_highlight
21248                    .range
21249                    .end
21250                    .cmp(&range.start, &snapshot)
21251                    .is_ge()
21252                {
21253                    ix -= 1;
21254                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
21255                        prev_highlight.range.end = range.end;
21256                    }
21257                    merged = true;
21258                    prev_highlight.index = index;
21259                    prev_highlight.color = color;
21260                    prev_highlight.options = options;
21261                }
21262            }
21263
21264            if !merged {
21265                row_highlights.insert(
21266                    ix,
21267                    RowHighlight {
21268                        range,
21269                        index,
21270                        color,
21271                        options,
21272                        type_id: TypeId::of::<T>(),
21273                    },
21274                );
21275            }
21276
21277            // If any of the following highlights intersect with this one, merge them.
21278            while let Some(next_highlight) = row_highlights.get(ix + 1) {
21279                let highlight = &row_highlights[ix];
21280                if next_highlight
21281                    .range
21282                    .start
21283                    .cmp(&highlight.range.end, &snapshot)
21284                    .is_le()
21285                {
21286                    if next_highlight
21287                        .range
21288                        .end
21289                        .cmp(&highlight.range.end, &snapshot)
21290                        .is_gt()
21291                    {
21292                        row_highlights[ix].range.end = next_highlight.range.end;
21293                    }
21294                    row_highlights.remove(ix + 1);
21295                } else {
21296                    break;
21297                }
21298            }
21299        }
21300    }
21301
21302    /// Remove any highlighted row ranges of the given type that intersect the
21303    /// given ranges.
21304    pub fn remove_highlighted_rows<T: 'static>(
21305        &mut self,
21306        ranges_to_remove: Vec<Range<Anchor>>,
21307        cx: &mut Context<Self>,
21308    ) {
21309        let snapshot = self.buffer().read(cx).snapshot(cx);
21310        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21311        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21312        row_highlights.retain(|highlight| {
21313            while let Some(range_to_remove) = ranges_to_remove.peek() {
21314                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
21315                    Ordering::Less | Ordering::Equal => {
21316                        ranges_to_remove.next();
21317                    }
21318                    Ordering::Greater => {
21319                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
21320                            Ordering::Less | Ordering::Equal => {
21321                                return false;
21322                            }
21323                            Ordering::Greater => break,
21324                        }
21325                    }
21326                }
21327            }
21328
21329            true
21330        })
21331    }
21332
21333    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
21334    pub fn clear_row_highlights<T: 'static>(&mut self) {
21335        self.highlighted_rows.remove(&TypeId::of::<T>());
21336    }
21337
21338    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
21339    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
21340        self.highlighted_rows
21341            .get(&TypeId::of::<T>())
21342            .map_or(&[] as &[_], |vec| vec.as_slice())
21343            .iter()
21344            .map(|highlight| (highlight.range.clone(), highlight.color))
21345    }
21346
21347    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
21348    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
21349    /// Allows to ignore certain kinds of highlights.
21350    pub fn highlighted_display_rows(
21351        &self,
21352        window: &mut Window,
21353        cx: &mut App,
21354    ) -> BTreeMap<DisplayRow, LineHighlight> {
21355        let snapshot = self.snapshot(window, cx);
21356        let mut used_highlight_orders = HashMap::default();
21357        self.highlighted_rows
21358            .iter()
21359            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
21360            .fold(
21361                BTreeMap::<DisplayRow, LineHighlight>::new(),
21362                |mut unique_rows, highlight| {
21363                    let start = highlight.range.start.to_display_point(&snapshot);
21364                    let end = highlight.range.end.to_display_point(&snapshot);
21365                    let start_row = start.row().0;
21366                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
21367                    {
21368                        end.row().0.saturating_sub(1)
21369                    } else {
21370                        end.row().0
21371                    };
21372                    for row in start_row..=end_row {
21373                        let used_index =
21374                            used_highlight_orders.entry(row).or_insert(highlight.index);
21375                        if highlight.index >= *used_index {
21376                            *used_index = highlight.index;
21377                            unique_rows.insert(
21378                                DisplayRow(row),
21379                                LineHighlight {
21380                                    include_gutter: highlight.options.include_gutter,
21381                                    border: None,
21382                                    background: highlight.color.into(),
21383                                    type_id: Some(highlight.type_id),
21384                                },
21385                            );
21386                        }
21387                    }
21388                    unique_rows
21389                },
21390            )
21391    }
21392
21393    pub fn highlighted_display_row_for_autoscroll(
21394        &self,
21395        snapshot: &DisplaySnapshot,
21396    ) -> Option<DisplayRow> {
21397        self.highlighted_rows
21398            .values()
21399            .flat_map(|highlighted_rows| highlighted_rows.iter())
21400            .filter_map(|highlight| {
21401                if highlight.options.autoscroll {
21402                    Some(highlight.range.start.to_display_point(snapshot).row())
21403                } else {
21404                    None
21405                }
21406            })
21407            .min()
21408    }
21409
21410    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21411        self.highlight_background::<SearchWithinRange>(
21412            ranges,
21413            |_, colors| colors.colors().editor_document_highlight_read_background,
21414            cx,
21415        )
21416    }
21417
21418    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21419        self.breadcrumb_header = Some(new_header);
21420    }
21421
21422    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21423        self.clear_background_highlights::<SearchWithinRange>(cx);
21424    }
21425
21426    pub fn highlight_background<T: 'static>(
21427        &mut self,
21428        ranges: &[Range<Anchor>],
21429        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21430        cx: &mut Context<Self>,
21431    ) {
21432        self.background_highlights.insert(
21433            HighlightKey::Type(TypeId::of::<T>()),
21434            (Arc::new(color_fetcher), Arc::from(ranges)),
21435        );
21436        self.scrollbar_marker_state.dirty = true;
21437        cx.notify();
21438    }
21439
21440    pub fn highlight_background_key<T: 'static>(
21441        &mut self,
21442        key: usize,
21443        ranges: &[Range<Anchor>],
21444        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21445        cx: &mut Context<Self>,
21446    ) {
21447        self.background_highlights.insert(
21448            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21449            (Arc::new(color_fetcher), Arc::from(ranges)),
21450        );
21451        self.scrollbar_marker_state.dirty = true;
21452        cx.notify();
21453    }
21454
21455    pub fn clear_background_highlights<T: 'static>(
21456        &mut self,
21457        cx: &mut Context<Self>,
21458    ) -> Option<BackgroundHighlight> {
21459        let text_highlights = self
21460            .background_highlights
21461            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21462        if !text_highlights.1.is_empty() {
21463            self.scrollbar_marker_state.dirty = true;
21464            cx.notify();
21465        }
21466        Some(text_highlights)
21467    }
21468
21469    pub fn highlight_gutter<T: 'static>(
21470        &mut self,
21471        ranges: impl Into<Vec<Range<Anchor>>>,
21472        color_fetcher: fn(&App) -> Hsla,
21473        cx: &mut Context<Self>,
21474    ) {
21475        self.gutter_highlights
21476            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21477        cx.notify();
21478    }
21479
21480    pub fn clear_gutter_highlights<T: 'static>(
21481        &mut self,
21482        cx: &mut Context<Self>,
21483    ) -> Option<GutterHighlight> {
21484        cx.notify();
21485        self.gutter_highlights.remove(&TypeId::of::<T>())
21486    }
21487
21488    pub fn insert_gutter_highlight<T: 'static>(
21489        &mut self,
21490        range: Range<Anchor>,
21491        color_fetcher: fn(&App) -> Hsla,
21492        cx: &mut Context<Self>,
21493    ) {
21494        let snapshot = self.buffer().read(cx).snapshot(cx);
21495        let mut highlights = self
21496            .gutter_highlights
21497            .remove(&TypeId::of::<T>())
21498            .map(|(_, highlights)| highlights)
21499            .unwrap_or_default();
21500        let ix = highlights.binary_search_by(|highlight| {
21501            Ordering::Equal
21502                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21503                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21504        });
21505        if let Err(ix) = ix {
21506            highlights.insert(ix, range);
21507        }
21508        self.gutter_highlights
21509            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21510    }
21511
21512    pub fn remove_gutter_highlights<T: 'static>(
21513        &mut self,
21514        ranges_to_remove: Vec<Range<Anchor>>,
21515        cx: &mut Context<Self>,
21516    ) {
21517        let snapshot = self.buffer().read(cx).snapshot(cx);
21518        let Some((color_fetcher, mut gutter_highlights)) =
21519            self.gutter_highlights.remove(&TypeId::of::<T>())
21520        else {
21521            return;
21522        };
21523        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21524        gutter_highlights.retain(|highlight| {
21525            while let Some(range_to_remove) = ranges_to_remove.peek() {
21526                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21527                    Ordering::Less | Ordering::Equal => {
21528                        ranges_to_remove.next();
21529                    }
21530                    Ordering::Greater => {
21531                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21532                            Ordering::Less | Ordering::Equal => {
21533                                return false;
21534                            }
21535                            Ordering::Greater => break,
21536                        }
21537                    }
21538                }
21539            }
21540
21541            true
21542        });
21543        self.gutter_highlights
21544            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21545    }
21546
21547    #[cfg(feature = "test-support")]
21548    pub fn all_text_highlights(
21549        &self,
21550        window: &mut Window,
21551        cx: &mut Context<Self>,
21552    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21553        let snapshot = self.snapshot(window, cx);
21554        self.display_map.update(cx, |display_map, _| {
21555            display_map
21556                .all_text_highlights()
21557                .map(|highlight| {
21558                    let (style, ranges) = highlight.as_ref();
21559                    (
21560                        *style,
21561                        ranges
21562                            .iter()
21563                            .map(|range| range.clone().to_display_points(&snapshot))
21564                            .collect(),
21565                    )
21566                })
21567                .collect()
21568        })
21569    }
21570
21571    #[cfg(feature = "test-support")]
21572    pub fn all_text_background_highlights(
21573        &self,
21574        window: &mut Window,
21575        cx: &mut Context<Self>,
21576    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21577        let snapshot = self.snapshot(window, cx);
21578        let buffer = &snapshot.buffer_snapshot();
21579        let start = buffer.anchor_before(MultiBufferOffset(0));
21580        let end = buffer.anchor_after(buffer.len());
21581        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21582    }
21583
21584    #[cfg(any(test, feature = "test-support"))]
21585    pub fn sorted_background_highlights_in_range(
21586        &self,
21587        search_range: Range<Anchor>,
21588        display_snapshot: &DisplaySnapshot,
21589        theme: &Theme,
21590    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21591        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21592        res.sort_by(|a, b| {
21593            a.0.start
21594                .cmp(&b.0.start)
21595                .then_with(|| a.0.end.cmp(&b.0.end))
21596                .then_with(|| a.1.cmp(&b.1))
21597        });
21598        res
21599    }
21600
21601    #[cfg(feature = "test-support")]
21602    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21603        let snapshot = self.buffer().read(cx).snapshot(cx);
21604
21605        let highlights = self
21606            .background_highlights
21607            .get(&HighlightKey::Type(TypeId::of::<
21608                items::BufferSearchHighlights,
21609            >()));
21610
21611        if let Some((_color, ranges)) = highlights {
21612            ranges
21613                .iter()
21614                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21615                .collect_vec()
21616        } else {
21617            vec![]
21618        }
21619    }
21620
21621    fn document_highlights_for_position<'a>(
21622        &'a self,
21623        position: Anchor,
21624        buffer: &'a MultiBufferSnapshot,
21625    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21626        let read_highlights = self
21627            .background_highlights
21628            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21629            .map(|h| &h.1);
21630        let write_highlights = self
21631            .background_highlights
21632            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21633            .map(|h| &h.1);
21634        let left_position = position.bias_left(buffer);
21635        let right_position = position.bias_right(buffer);
21636        read_highlights
21637            .into_iter()
21638            .chain(write_highlights)
21639            .flat_map(move |ranges| {
21640                let start_ix = match ranges.binary_search_by(|probe| {
21641                    let cmp = probe.end.cmp(&left_position, buffer);
21642                    if cmp.is_ge() {
21643                        Ordering::Greater
21644                    } else {
21645                        Ordering::Less
21646                    }
21647                }) {
21648                    Ok(i) | Err(i) => i,
21649                };
21650
21651                ranges[start_ix..]
21652                    .iter()
21653                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21654            })
21655    }
21656
21657    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21658        self.background_highlights
21659            .get(&HighlightKey::Type(TypeId::of::<T>()))
21660            .is_some_and(|(_, highlights)| !highlights.is_empty())
21661    }
21662
21663    /// Returns all background highlights for a given range.
21664    ///
21665    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21666    pub fn background_highlights_in_range(
21667        &self,
21668        search_range: Range<Anchor>,
21669        display_snapshot: &DisplaySnapshot,
21670        theme: &Theme,
21671    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21672        let mut results = Vec::new();
21673        for (color_fetcher, ranges) in self.background_highlights.values() {
21674            let start_ix = match ranges.binary_search_by(|probe| {
21675                let cmp = probe
21676                    .end
21677                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21678                if cmp.is_gt() {
21679                    Ordering::Greater
21680                } else {
21681                    Ordering::Less
21682                }
21683            }) {
21684                Ok(i) | Err(i) => i,
21685            };
21686            for (index, range) in ranges[start_ix..].iter().enumerate() {
21687                if range
21688                    .start
21689                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21690                    .is_ge()
21691                {
21692                    break;
21693                }
21694
21695                let color = color_fetcher(&(start_ix + index), theme);
21696                let start = range.start.to_display_point(display_snapshot);
21697                let end = range.end.to_display_point(display_snapshot);
21698                results.push((start..end, color))
21699            }
21700        }
21701        results
21702    }
21703
21704    pub fn gutter_highlights_in_range(
21705        &self,
21706        search_range: Range<Anchor>,
21707        display_snapshot: &DisplaySnapshot,
21708        cx: &App,
21709    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21710        let mut results = Vec::new();
21711        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21712            let color = color_fetcher(cx);
21713            let start_ix = match ranges.binary_search_by(|probe| {
21714                let cmp = probe
21715                    .end
21716                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21717                if cmp.is_gt() {
21718                    Ordering::Greater
21719                } else {
21720                    Ordering::Less
21721                }
21722            }) {
21723                Ok(i) | Err(i) => i,
21724            };
21725            for range in &ranges[start_ix..] {
21726                if range
21727                    .start
21728                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21729                    .is_ge()
21730                {
21731                    break;
21732                }
21733
21734                let start = range.start.to_display_point(display_snapshot);
21735                let end = range.end.to_display_point(display_snapshot);
21736                results.push((start..end, color))
21737            }
21738        }
21739        results
21740    }
21741
21742    /// Get the text ranges corresponding to the redaction query
21743    pub fn redacted_ranges(
21744        &self,
21745        search_range: Range<Anchor>,
21746        display_snapshot: &DisplaySnapshot,
21747        cx: &App,
21748    ) -> Vec<Range<DisplayPoint>> {
21749        display_snapshot
21750            .buffer_snapshot()
21751            .redacted_ranges(search_range, |file| {
21752                if let Some(file) = file {
21753                    file.is_private()
21754                        && EditorSettings::get(
21755                            Some(SettingsLocation {
21756                                worktree_id: file.worktree_id(cx),
21757                                path: file.path().as_ref(),
21758                            }),
21759                            cx,
21760                        )
21761                        .redact_private_values
21762                } else {
21763                    false
21764                }
21765            })
21766            .map(|range| {
21767                range.start.to_display_point(display_snapshot)
21768                    ..range.end.to_display_point(display_snapshot)
21769            })
21770            .collect()
21771    }
21772
21773    pub fn highlight_text_key<T: 'static>(
21774        &mut self,
21775        key: usize,
21776        ranges: Vec<Range<Anchor>>,
21777        style: HighlightStyle,
21778        merge: bool,
21779        cx: &mut Context<Self>,
21780    ) {
21781        self.display_map.update(cx, |map, cx| {
21782            map.highlight_text(
21783                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21784                ranges,
21785                style,
21786                merge,
21787                cx,
21788            );
21789        });
21790        cx.notify();
21791    }
21792
21793    pub fn highlight_text<T: 'static>(
21794        &mut self,
21795        ranges: Vec<Range<Anchor>>,
21796        style: HighlightStyle,
21797        cx: &mut Context<Self>,
21798    ) {
21799        self.display_map.update(cx, |map, cx| {
21800            map.highlight_text(
21801                HighlightKey::Type(TypeId::of::<T>()),
21802                ranges,
21803                style,
21804                false,
21805                cx,
21806            )
21807        });
21808        cx.notify();
21809    }
21810
21811    pub fn text_highlights<'a, T: 'static>(
21812        &'a self,
21813        cx: &'a App,
21814    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21815        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21816    }
21817
21818    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21819        let cleared = self
21820            .display_map
21821            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21822        if cleared {
21823            cx.notify();
21824        }
21825    }
21826
21827    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21828        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21829            && self.focus_handle.is_focused(window)
21830    }
21831
21832    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21833        self.show_cursor_when_unfocused = is_enabled;
21834        cx.notify();
21835    }
21836
21837    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21838        cx.notify();
21839    }
21840
21841    fn on_debug_session_event(
21842        &mut self,
21843        _session: Entity<Session>,
21844        event: &SessionEvent,
21845        cx: &mut Context<Self>,
21846    ) {
21847        if let SessionEvent::InvalidateInlineValue = event {
21848            self.refresh_inline_values(cx);
21849        }
21850    }
21851
21852    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21853        let Some(project) = self.project.clone() else {
21854            return;
21855        };
21856
21857        if !self.inline_value_cache.enabled {
21858            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21859            self.splice_inlays(&inlays, Vec::new(), cx);
21860            return;
21861        }
21862
21863        let current_execution_position = self
21864            .highlighted_rows
21865            .get(&TypeId::of::<ActiveDebugLine>())
21866            .and_then(|lines| lines.last().map(|line| line.range.end));
21867
21868        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21869            let inline_values = editor
21870                .update(cx, |editor, cx| {
21871                    let Some(current_execution_position) = current_execution_position else {
21872                        return Some(Task::ready(Ok(Vec::new())));
21873                    };
21874
21875                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21876                        let snapshot = buffer.snapshot(cx);
21877
21878                        let excerpt = snapshot.excerpt_containing(
21879                            current_execution_position..current_execution_position,
21880                        )?;
21881
21882                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21883                    })?;
21884
21885                    let range =
21886                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21887
21888                    project.inline_values(buffer, range, cx)
21889                })
21890                .ok()
21891                .flatten()?
21892                .await
21893                .context("refreshing debugger inlays")
21894                .log_err()?;
21895
21896            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21897
21898            for (buffer_id, inline_value) in inline_values
21899                .into_iter()
21900                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21901            {
21902                buffer_inline_values
21903                    .entry(buffer_id)
21904                    .or_default()
21905                    .push(inline_value);
21906            }
21907
21908            editor
21909                .update(cx, |editor, cx| {
21910                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21911                    let mut new_inlays = Vec::default();
21912
21913                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21914                        let buffer_id = buffer_snapshot.remote_id();
21915                        buffer_inline_values
21916                            .get(&buffer_id)
21917                            .into_iter()
21918                            .flatten()
21919                            .for_each(|hint| {
21920                                let inlay = Inlay::debugger(
21921                                    post_inc(&mut editor.next_inlay_id),
21922                                    Anchor::in_buffer(excerpt_id, hint.position),
21923                                    hint.text(),
21924                                );
21925                                if !inlay.text().chars().contains(&'\n') {
21926                                    new_inlays.push(inlay);
21927                                }
21928                            });
21929                    }
21930
21931                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21932                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21933
21934                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21935                })
21936                .ok()?;
21937            Some(())
21938        });
21939    }
21940
21941    fn on_buffer_event(
21942        &mut self,
21943        multibuffer: &Entity<MultiBuffer>,
21944        event: &multi_buffer::Event,
21945        window: &mut Window,
21946        cx: &mut Context<Self>,
21947    ) {
21948        match event {
21949            multi_buffer::Event::Edited { edited_buffer } => {
21950                self.scrollbar_marker_state.dirty = true;
21951                self.active_indent_guides_state.dirty = true;
21952                self.refresh_active_diagnostics(cx);
21953                self.refresh_code_actions(window, cx);
21954                self.refresh_single_line_folds(window, cx);
21955                self.refresh_matching_bracket_highlights(window, cx);
21956                if self.has_active_edit_prediction() {
21957                    self.update_visible_edit_prediction(window, cx);
21958                }
21959
21960                if let Some(buffer) = edited_buffer {
21961                    if buffer.read(cx).file().is_none() {
21962                        cx.emit(EditorEvent::TitleChanged);
21963                    }
21964
21965                    if self.project.is_some() {
21966                        let buffer_id = buffer.read(cx).remote_id();
21967                        self.register_buffer(buffer_id, cx);
21968                        self.update_lsp_data(Some(buffer_id), window, cx);
21969                        self.refresh_inlay_hints(
21970                            InlayHintRefreshReason::BufferEdited(buffer_id),
21971                            cx,
21972                        );
21973                    }
21974                }
21975
21976                cx.emit(EditorEvent::BufferEdited);
21977                cx.emit(SearchEvent::MatchesInvalidated);
21978
21979                let Some(project) = &self.project else { return };
21980                let (telemetry, is_via_ssh) = {
21981                    let project = project.read(cx);
21982                    let telemetry = project.client().telemetry().clone();
21983                    let is_via_ssh = project.is_via_remote_server();
21984                    (telemetry, is_via_ssh)
21985                };
21986                telemetry.log_edit_event("editor", is_via_ssh);
21987            }
21988            multi_buffer::Event::ExcerptsAdded {
21989                buffer,
21990                predecessor,
21991                excerpts,
21992            } => {
21993                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21994                let buffer_id = buffer.read(cx).remote_id();
21995                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21996                    && let Some(project) = &self.project
21997                {
21998                    update_uncommitted_diff_for_buffer(
21999                        cx.entity(),
22000                        project,
22001                        [buffer.clone()],
22002                        self.buffer.clone(),
22003                        cx,
22004                    )
22005                    .detach();
22006                }
22007                self.update_lsp_data(Some(buffer_id), window, cx);
22008                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22009                self.colorize_brackets(false, cx);
22010                cx.emit(EditorEvent::ExcerptsAdded {
22011                    buffer: buffer.clone(),
22012                    predecessor: *predecessor,
22013                    excerpts: excerpts.clone(),
22014                });
22015            }
22016            multi_buffer::Event::ExcerptsRemoved {
22017                ids,
22018                removed_buffer_ids,
22019            } => {
22020                if let Some(inlay_hints) = &mut self.inlay_hints {
22021                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
22022                }
22023                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
22024                for buffer_id in removed_buffer_ids {
22025                    self.registered_buffers.remove(buffer_id);
22026                }
22027                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22028                cx.emit(EditorEvent::ExcerptsRemoved {
22029                    ids: ids.clone(),
22030                    removed_buffer_ids: removed_buffer_ids.clone(),
22031                });
22032            }
22033            multi_buffer::Event::ExcerptsEdited {
22034                excerpt_ids,
22035                buffer_ids,
22036            } => {
22037                self.display_map.update(cx, |map, cx| {
22038                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
22039                });
22040                cx.emit(EditorEvent::ExcerptsEdited {
22041                    ids: excerpt_ids.clone(),
22042                });
22043            }
22044            multi_buffer::Event::ExcerptsExpanded { ids } => {
22045                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22046                self.refresh_document_highlights(cx);
22047                for id in ids {
22048                    self.fetched_tree_sitter_chunks.remove(id);
22049                }
22050                self.colorize_brackets(false, cx);
22051                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
22052            }
22053            multi_buffer::Event::Reparsed(buffer_id) => {
22054                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22055                self.refresh_selected_text_highlights(true, window, cx);
22056                self.colorize_brackets(true, cx);
22057                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22058
22059                cx.emit(EditorEvent::Reparsed(*buffer_id));
22060            }
22061            multi_buffer::Event::DiffHunksToggled => {
22062                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22063            }
22064            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
22065                if !is_fresh_language {
22066                    self.registered_buffers.remove(&buffer_id);
22067                }
22068                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22069                cx.emit(EditorEvent::Reparsed(*buffer_id));
22070                cx.notify();
22071            }
22072            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
22073            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
22074            multi_buffer::Event::FileHandleChanged
22075            | multi_buffer::Event::Reloaded
22076            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
22077            multi_buffer::Event::DiagnosticsUpdated => {
22078                self.update_diagnostics_state(window, cx);
22079            }
22080            _ => {}
22081        };
22082    }
22083
22084    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
22085        if !self.diagnostics_enabled() {
22086            return;
22087        }
22088        self.refresh_active_diagnostics(cx);
22089        self.refresh_inline_diagnostics(true, window, cx);
22090        self.scrollbar_marker_state.dirty = true;
22091        cx.notify();
22092    }
22093
22094    pub fn start_temporary_diff_override(&mut self) {
22095        self.load_diff_task.take();
22096        self.temporary_diff_override = true;
22097    }
22098
22099    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
22100        self.temporary_diff_override = false;
22101        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
22102        self.buffer.update(cx, |buffer, cx| {
22103            buffer.set_all_diff_hunks_collapsed(cx);
22104        });
22105
22106        if let Some(project) = self.project.clone() {
22107            self.load_diff_task = Some(
22108                update_uncommitted_diff_for_buffer(
22109                    cx.entity(),
22110                    &project,
22111                    self.buffer.read(cx).all_buffers(),
22112                    self.buffer.clone(),
22113                    cx,
22114                )
22115                .shared(),
22116            );
22117        }
22118    }
22119
22120    fn on_display_map_changed(
22121        &mut self,
22122        _: Entity<DisplayMap>,
22123        _: &mut Window,
22124        cx: &mut Context<Self>,
22125    ) {
22126        cx.notify();
22127    }
22128
22129    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
22130        if !self.mode.is_full() {
22131            return None;
22132        }
22133
22134        let theme_settings = theme::ThemeSettings::get_global(cx);
22135        let theme = cx.theme();
22136        let accent_colors = theme.accents().clone();
22137
22138        let accent_overrides = theme_settings
22139            .theme_overrides
22140            .get(theme.name.as_ref())
22141            .map(|theme_style| &theme_style.accents)
22142            .into_iter()
22143            .flatten()
22144            .chain(
22145                theme_settings
22146                    .experimental_theme_overrides
22147                    .as_ref()
22148                    .map(|overrides| &overrides.accents)
22149                    .into_iter()
22150                    .flatten(),
22151            )
22152            .flat_map(|accent| accent.0.clone())
22153            .collect();
22154
22155        Some(AccentData {
22156            colors: accent_colors,
22157            overrides: accent_overrides,
22158        })
22159    }
22160
22161    fn fetch_applicable_language_settings(
22162        &self,
22163        cx: &App,
22164    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
22165        if !self.mode.is_full() {
22166            return HashMap::default();
22167        }
22168
22169        self.buffer().read(cx).all_buffers().into_iter().fold(
22170            HashMap::default(),
22171            |mut acc, buffer| {
22172                let buffer = buffer.read(cx);
22173                let language = buffer.language().map(|language| language.name());
22174                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
22175                    let file = buffer.file();
22176                    v.insert(language_settings(language, file, cx).into_owned());
22177                }
22178                acc
22179            },
22180        )
22181    }
22182
22183    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22184        let new_language_settings = self.fetch_applicable_language_settings(cx);
22185        let language_settings_changed = new_language_settings != self.applicable_language_settings;
22186        self.applicable_language_settings = new_language_settings;
22187
22188        let new_accents = self.fetch_accent_data(cx);
22189        let accents_changed = new_accents != self.accent_data;
22190        self.accent_data = new_accents;
22191
22192        if self.diagnostics_enabled() {
22193            let new_severity = EditorSettings::get_global(cx)
22194                .diagnostics_max_severity
22195                .unwrap_or(DiagnosticSeverity::Hint);
22196            self.set_max_diagnostics_severity(new_severity, cx);
22197        }
22198        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22199        self.update_edit_prediction_settings(cx);
22200        self.refresh_edit_prediction(true, false, window, cx);
22201        self.refresh_inline_values(cx);
22202        self.refresh_inlay_hints(
22203            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
22204                self.selections.newest_anchor().head(),
22205                &self.buffer.read(cx).snapshot(cx),
22206                cx,
22207            )),
22208            cx,
22209        );
22210
22211        let old_cursor_shape = self.cursor_shape;
22212        let old_show_breadcrumbs = self.show_breadcrumbs;
22213
22214        {
22215            let editor_settings = EditorSettings::get_global(cx);
22216            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
22217            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
22218            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
22219            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
22220        }
22221
22222        if old_cursor_shape != self.cursor_shape {
22223            cx.emit(EditorEvent::CursorShapeChanged);
22224        }
22225
22226        if old_show_breadcrumbs != self.show_breadcrumbs {
22227            cx.emit(EditorEvent::BreadcrumbsChanged);
22228        }
22229
22230        let project_settings = ProjectSettings::get_global(cx);
22231        self.buffer_serialization = self
22232            .should_serialize_buffer()
22233            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
22234
22235        if self.mode.is_full() {
22236            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
22237            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
22238            if self.show_inline_diagnostics != show_inline_diagnostics {
22239                self.show_inline_diagnostics = show_inline_diagnostics;
22240                self.refresh_inline_diagnostics(false, window, cx);
22241            }
22242
22243            if self.git_blame_inline_enabled != inline_blame_enabled {
22244                self.toggle_git_blame_inline_internal(false, window, cx);
22245            }
22246
22247            let minimap_settings = EditorSettings::get_global(cx).minimap;
22248            if self.minimap_visibility != MinimapVisibility::Disabled {
22249                if self.minimap_visibility.settings_visibility()
22250                    != minimap_settings.minimap_enabled()
22251                {
22252                    self.set_minimap_visibility(
22253                        MinimapVisibility::for_mode(self.mode(), cx),
22254                        window,
22255                        cx,
22256                    );
22257                } else if let Some(minimap_entity) = self.minimap.as_ref() {
22258                    minimap_entity.update(cx, |minimap_editor, cx| {
22259                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
22260                    })
22261                }
22262            }
22263
22264            if language_settings_changed || accents_changed {
22265                self.colorize_brackets(true, cx);
22266            }
22267
22268            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
22269                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
22270            }) {
22271                if !inlay_splice.is_empty() {
22272                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
22273                }
22274                self.refresh_colors_for_visible_range(None, window, cx);
22275            }
22276        }
22277
22278        cx.notify();
22279    }
22280
22281    pub fn set_searchable(&mut self, searchable: bool) {
22282        self.searchable = searchable;
22283    }
22284
22285    pub fn searchable(&self) -> bool {
22286        self.searchable
22287    }
22288
22289    pub fn open_excerpts_in_split(
22290        &mut self,
22291        _: &OpenExcerptsSplit,
22292        window: &mut Window,
22293        cx: &mut Context<Self>,
22294    ) {
22295        self.open_excerpts_common(None, true, window, cx)
22296    }
22297
22298    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
22299        self.open_excerpts_common(None, false, window, cx)
22300    }
22301
22302    fn open_excerpts_common(
22303        &mut self,
22304        jump_data: Option<JumpData>,
22305        split: bool,
22306        window: &mut Window,
22307        cx: &mut Context<Self>,
22308    ) {
22309        let Some(workspace) = self.workspace() else {
22310            cx.propagate();
22311            return;
22312        };
22313
22314        if self.buffer.read(cx).is_singleton() {
22315            cx.propagate();
22316            return;
22317        }
22318
22319        let mut new_selections_by_buffer = HashMap::default();
22320        match &jump_data {
22321            Some(JumpData::MultiBufferPoint {
22322                excerpt_id,
22323                position,
22324                anchor,
22325                line_offset_from_top,
22326            }) => {
22327                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22328                if let Some(buffer) = multi_buffer_snapshot
22329                    .buffer_id_for_excerpt(*excerpt_id)
22330                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
22331                {
22332                    let buffer_snapshot = buffer.read(cx).snapshot();
22333                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
22334                        language::ToPoint::to_point(anchor, &buffer_snapshot)
22335                    } else {
22336                        buffer_snapshot.clip_point(*position, Bias::Left)
22337                    };
22338                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
22339                    new_selections_by_buffer.insert(
22340                        buffer,
22341                        (
22342                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
22343                            Some(*line_offset_from_top),
22344                        ),
22345                    );
22346                }
22347            }
22348            Some(JumpData::MultiBufferRow {
22349                row,
22350                line_offset_from_top,
22351            }) => {
22352                let point = MultiBufferPoint::new(row.0, 0);
22353                if let Some((buffer, buffer_point, _)) =
22354                    self.buffer.read(cx).point_to_buffer_point(point, cx)
22355                {
22356                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
22357                    new_selections_by_buffer
22358                        .entry(buffer)
22359                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
22360                        .0
22361                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
22362                }
22363            }
22364            None => {
22365                let selections = self
22366                    .selections
22367                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
22368                let multi_buffer = self.buffer.read(cx);
22369                for selection in selections {
22370                    for (snapshot, range, _, anchor) in multi_buffer
22371                        .snapshot(cx)
22372                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
22373                    {
22374                        if let Some(anchor) = anchor {
22375                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
22376                            else {
22377                                continue;
22378                            };
22379                            let offset = text::ToOffset::to_offset(
22380                                &anchor.text_anchor,
22381                                &buffer_handle.read(cx).snapshot(),
22382                            );
22383                            let range = BufferOffset(offset)..BufferOffset(offset);
22384                            new_selections_by_buffer
22385                                .entry(buffer_handle)
22386                                .or_insert((Vec::new(), None))
22387                                .0
22388                                .push(range)
22389                        } else {
22390                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22391                            else {
22392                                continue;
22393                            };
22394                            new_selections_by_buffer
22395                                .entry(buffer_handle)
22396                                .or_insert((Vec::new(), None))
22397                                .0
22398                                .push(range)
22399                        }
22400                    }
22401                }
22402            }
22403        }
22404
22405        new_selections_by_buffer
22406            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
22407
22408        if new_selections_by_buffer.is_empty() {
22409            return;
22410        }
22411
22412        // We defer the pane interaction because we ourselves are a workspace item
22413        // and activating a new item causes the pane to call a method on us reentrantly,
22414        // which panics if we're on the stack.
22415        window.defer(cx, move |window, cx| {
22416            workspace.update(cx, |workspace, cx| {
22417                let pane = if split {
22418                    workspace.adjacent_pane(window, cx)
22419                } else {
22420                    workspace.active_pane().clone()
22421                };
22422
22423                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22424                    let buffer_read = buffer.read(cx);
22425                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22426                        (true, project::File::from_dyn(Some(file)).is_some())
22427                    } else {
22428                        (false, false)
22429                    };
22430
22431                    // If project file is none workspace.open_project_item will fail to open the excerpt
22432                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22433                    // so we check if there's a tab match in that case first
22434                    let editor = (!has_file || !is_project_file)
22435                        .then(|| {
22436                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22437                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22438                            // Instead, we try to activate the existing editor in the pane first.
22439                            let (editor, pane_item_index, pane_item_id) =
22440                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22441                                    let editor = item.downcast::<Editor>()?;
22442                                    let singleton_buffer =
22443                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22444                                    if singleton_buffer == buffer {
22445                                        Some((editor, i, item.item_id()))
22446                                    } else {
22447                                        None
22448                                    }
22449                                })?;
22450                            pane.update(cx, |pane, cx| {
22451                                pane.activate_item(pane_item_index, true, true, window, cx);
22452                                if !PreviewTabsSettings::get_global(cx)
22453                                    .enable_preview_from_multibuffer
22454                                {
22455                                    pane.unpreview_item_if_preview(pane_item_id);
22456                                }
22457                            });
22458                            Some(editor)
22459                        })
22460                        .flatten()
22461                        .unwrap_or_else(|| {
22462                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22463                                .enable_keep_preview_on_code_navigation;
22464                            let allow_new_preview =
22465                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22466                            workspace.open_project_item::<Self>(
22467                                pane.clone(),
22468                                buffer,
22469                                true,
22470                                true,
22471                                keep_old_preview,
22472                                allow_new_preview,
22473                                window,
22474                                cx,
22475                            )
22476                        });
22477
22478                    editor.update(cx, |editor, cx| {
22479                        if has_file && !is_project_file {
22480                            editor.set_read_only(true);
22481                        }
22482                        let autoscroll = match scroll_offset {
22483                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22484                            None => Autoscroll::newest(),
22485                        };
22486                        let nav_history = editor.nav_history.take();
22487                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
22488                        let Some((&excerpt_id, _, buffer_snapshot)) =
22489                            multibuffer_snapshot.as_singleton()
22490                        else {
22491                            return;
22492                        };
22493                        editor.change_selections(
22494                            SelectionEffects::scroll(autoscroll),
22495                            window,
22496                            cx,
22497                            |s| {
22498                                s.select_ranges(ranges.into_iter().map(|range| {
22499                                    let range = buffer_snapshot.anchor_before(range.start)
22500                                        ..buffer_snapshot.anchor_after(range.end);
22501                                    multibuffer_snapshot
22502                                        .anchor_range_in_excerpt(excerpt_id, range)
22503                                        .unwrap()
22504                                }));
22505                            },
22506                        );
22507                        editor.nav_history = nav_history;
22508                    });
22509                }
22510            })
22511        });
22512    }
22513
22514    // Allow opening excerpts for buffers that either belong to the current project
22515    // or represent synthetic/non-local files (e.g., git blobs). File-less buffers
22516    // are also supported so tests and other in-memory views keep working.
22517    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
22518        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some() || !file.is_local())
22519    }
22520
22521    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22522        let snapshot = self.buffer.read(cx).read(cx);
22523        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22524        Some(
22525            ranges
22526                .iter()
22527                .map(move |range| {
22528                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22529                })
22530                .collect(),
22531        )
22532    }
22533
22534    fn selection_replacement_ranges(
22535        &self,
22536        range: Range<MultiBufferOffsetUtf16>,
22537        cx: &mut App,
22538    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22539        let selections = self
22540            .selections
22541            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22542        let newest_selection = selections
22543            .iter()
22544            .max_by_key(|selection| selection.id)
22545            .unwrap();
22546        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22547        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22548        let snapshot = self.buffer.read(cx).read(cx);
22549        selections
22550            .into_iter()
22551            .map(|mut selection| {
22552                selection.start.0.0 =
22553                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22554                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22555                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22556                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22557            })
22558            .collect()
22559    }
22560
22561    fn report_editor_event(
22562        &self,
22563        reported_event: ReportEditorEvent,
22564        file_extension: Option<String>,
22565        cx: &App,
22566    ) {
22567        if cfg!(any(test, feature = "test-support")) {
22568            return;
22569        }
22570
22571        let Some(project) = &self.project else { return };
22572
22573        // If None, we are in a file without an extension
22574        let file = self
22575            .buffer
22576            .read(cx)
22577            .as_singleton()
22578            .and_then(|b| b.read(cx).file());
22579        let file_extension = file_extension.or(file
22580            .as_ref()
22581            .and_then(|file| Path::new(file.file_name(cx)).extension())
22582            .and_then(|e| e.to_str())
22583            .map(|a| a.to_string()));
22584
22585        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22586            .map(|vim_mode| vim_mode.0)
22587            .unwrap_or(false);
22588
22589        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22590        let copilot_enabled = edit_predictions_provider
22591            == language::language_settings::EditPredictionProvider::Copilot;
22592        let copilot_enabled_for_language = self
22593            .buffer
22594            .read(cx)
22595            .language_settings(cx)
22596            .show_edit_predictions;
22597
22598        let project = project.read(cx);
22599        let event_type = reported_event.event_type();
22600
22601        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22602            telemetry::event!(
22603                event_type,
22604                type = if auto_saved {"autosave"} else {"manual"},
22605                file_extension,
22606                vim_mode,
22607                copilot_enabled,
22608                copilot_enabled_for_language,
22609                edit_predictions_provider,
22610                is_via_ssh = project.is_via_remote_server(),
22611            );
22612        } else {
22613            telemetry::event!(
22614                event_type,
22615                file_extension,
22616                vim_mode,
22617                copilot_enabled,
22618                copilot_enabled_for_language,
22619                edit_predictions_provider,
22620                is_via_ssh = project.is_via_remote_server(),
22621            );
22622        };
22623    }
22624
22625    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22626    /// with each line being an array of {text, highlight} objects.
22627    fn copy_highlight_json(
22628        &mut self,
22629        _: &CopyHighlightJson,
22630        window: &mut Window,
22631        cx: &mut Context<Self>,
22632    ) {
22633        #[derive(Serialize)]
22634        struct Chunk<'a> {
22635            text: String,
22636            highlight: Option<&'a str>,
22637        }
22638
22639        let snapshot = self.buffer.read(cx).snapshot(cx);
22640        let range = self
22641            .selected_text_range(false, window, cx)
22642            .and_then(|selection| {
22643                if selection.range.is_empty() {
22644                    None
22645                } else {
22646                    Some(
22647                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22648                            selection.range.start,
22649                        )))
22650                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22651                                selection.range.end,
22652                            ))),
22653                    )
22654                }
22655            })
22656            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22657
22658        let chunks = snapshot.chunks(range, true);
22659        let mut lines = Vec::new();
22660        let mut line: VecDeque<Chunk> = VecDeque::new();
22661
22662        let Some(style) = self.style.as_ref() else {
22663            return;
22664        };
22665
22666        for chunk in chunks {
22667            let highlight = chunk
22668                .syntax_highlight_id
22669                .and_then(|id| id.name(&style.syntax));
22670            let mut chunk_lines = chunk.text.split('\n').peekable();
22671            while let Some(text) = chunk_lines.next() {
22672                let mut merged_with_last_token = false;
22673                if let Some(last_token) = line.back_mut()
22674                    && last_token.highlight == highlight
22675                {
22676                    last_token.text.push_str(text);
22677                    merged_with_last_token = true;
22678                }
22679
22680                if !merged_with_last_token {
22681                    line.push_back(Chunk {
22682                        text: text.into(),
22683                        highlight,
22684                    });
22685                }
22686
22687                if chunk_lines.peek().is_some() {
22688                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22689                        line.pop_front();
22690                    }
22691                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22692                        line.pop_back();
22693                    }
22694
22695                    lines.push(mem::take(&mut line));
22696                }
22697            }
22698        }
22699
22700        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22701            return;
22702        };
22703        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22704    }
22705
22706    pub fn open_context_menu(
22707        &mut self,
22708        _: &OpenContextMenu,
22709        window: &mut Window,
22710        cx: &mut Context<Self>,
22711    ) {
22712        self.request_autoscroll(Autoscroll::newest(), cx);
22713        let position = self
22714            .selections
22715            .newest_display(&self.display_snapshot(cx))
22716            .start;
22717        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22718    }
22719
22720    pub fn replay_insert_event(
22721        &mut self,
22722        text: &str,
22723        relative_utf16_range: Option<Range<isize>>,
22724        window: &mut Window,
22725        cx: &mut Context<Self>,
22726    ) {
22727        if !self.input_enabled {
22728            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22729            return;
22730        }
22731        if let Some(relative_utf16_range) = relative_utf16_range {
22732            let selections = self
22733                .selections
22734                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22735            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22736                let new_ranges = selections.into_iter().map(|range| {
22737                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22738                        range
22739                            .head()
22740                            .0
22741                            .0
22742                            .saturating_add_signed(relative_utf16_range.start),
22743                    ));
22744                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22745                        range
22746                            .head()
22747                            .0
22748                            .0
22749                            .saturating_add_signed(relative_utf16_range.end),
22750                    ));
22751                    start..end
22752                });
22753                s.select_ranges(new_ranges);
22754            });
22755        }
22756
22757        self.handle_input(text, window, cx);
22758    }
22759
22760    pub fn is_focused(&self, window: &Window) -> bool {
22761        self.focus_handle.is_focused(window)
22762    }
22763
22764    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22765        cx.emit(EditorEvent::Focused);
22766
22767        if let Some(descendant) = self
22768            .last_focused_descendant
22769            .take()
22770            .and_then(|descendant| descendant.upgrade())
22771        {
22772            window.focus(&descendant);
22773        } else {
22774            if let Some(blame) = self.blame.as_ref() {
22775                blame.update(cx, GitBlame::focus)
22776            }
22777
22778            self.blink_manager.update(cx, BlinkManager::enable);
22779            self.show_cursor_names(window, cx);
22780            self.buffer.update(cx, |buffer, cx| {
22781                buffer.finalize_last_transaction(cx);
22782                if self.leader_id.is_none() {
22783                    buffer.set_active_selections(
22784                        &self.selections.disjoint_anchors_arc(),
22785                        self.selections.line_mode(),
22786                        self.cursor_shape,
22787                        cx,
22788                    );
22789                }
22790            });
22791
22792            if let Some(position_map) = self.last_position_map.clone() {
22793                EditorElement::mouse_moved(
22794                    self,
22795                    &MouseMoveEvent {
22796                        position: window.mouse_position(),
22797                        pressed_button: None,
22798                        modifiers: window.modifiers(),
22799                    },
22800                    &position_map,
22801                    window,
22802                    cx,
22803                );
22804            }
22805        }
22806    }
22807
22808    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22809        cx.emit(EditorEvent::FocusedIn)
22810    }
22811
22812    fn handle_focus_out(
22813        &mut self,
22814        event: FocusOutEvent,
22815        _window: &mut Window,
22816        cx: &mut Context<Self>,
22817    ) {
22818        if event.blurred != self.focus_handle {
22819            self.last_focused_descendant = Some(event.blurred);
22820        }
22821        self.selection_drag_state = SelectionDragState::None;
22822        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22823    }
22824
22825    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22826        self.blink_manager.update(cx, BlinkManager::disable);
22827        self.buffer
22828            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22829
22830        if let Some(blame) = self.blame.as_ref() {
22831            blame.update(cx, GitBlame::blur)
22832        }
22833        if !self.hover_state.focused(window, cx) {
22834            hide_hover(self, cx);
22835        }
22836        if !self
22837            .context_menu
22838            .borrow()
22839            .as_ref()
22840            .is_some_and(|context_menu| context_menu.focused(window, cx))
22841        {
22842            self.hide_context_menu(window, cx);
22843        }
22844        self.take_active_edit_prediction(cx);
22845        cx.emit(EditorEvent::Blurred);
22846        cx.notify();
22847    }
22848
22849    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22850        let mut pending: String = window
22851            .pending_input_keystrokes()
22852            .into_iter()
22853            .flatten()
22854            .filter_map(|keystroke| keystroke.key_char.clone())
22855            .collect();
22856
22857        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22858            pending = "".to_string();
22859        }
22860
22861        let existing_pending = self
22862            .text_highlights::<PendingInput>(cx)
22863            .map(|(_, ranges)| ranges.to_vec());
22864        if existing_pending.is_none() && pending.is_empty() {
22865            return;
22866        }
22867        let transaction =
22868            self.transact(window, cx, |this, window, cx| {
22869                let selections = this
22870                    .selections
22871                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22872                let edits = selections
22873                    .iter()
22874                    .map(|selection| (selection.end..selection.end, pending.clone()));
22875                this.edit(edits, cx);
22876                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22877                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22878                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22879                    }));
22880                });
22881                if let Some(existing_ranges) = existing_pending {
22882                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22883                    this.edit(edits, cx);
22884                }
22885            });
22886
22887        let snapshot = self.snapshot(window, cx);
22888        let ranges = self
22889            .selections
22890            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22891            .into_iter()
22892            .map(|selection| {
22893                snapshot.buffer_snapshot().anchor_after(selection.end)
22894                    ..snapshot
22895                        .buffer_snapshot()
22896                        .anchor_before(selection.end + pending.len())
22897            })
22898            .collect();
22899
22900        if pending.is_empty() {
22901            self.clear_highlights::<PendingInput>(cx);
22902        } else {
22903            self.highlight_text::<PendingInput>(
22904                ranges,
22905                HighlightStyle {
22906                    underline: Some(UnderlineStyle {
22907                        thickness: px(1.),
22908                        color: None,
22909                        wavy: false,
22910                    }),
22911                    ..Default::default()
22912                },
22913                cx,
22914            );
22915        }
22916
22917        self.ime_transaction = self.ime_transaction.or(transaction);
22918        if let Some(transaction) = self.ime_transaction {
22919            self.buffer.update(cx, |buffer, cx| {
22920                buffer.group_until_transaction(transaction, cx);
22921            });
22922        }
22923
22924        if self.text_highlights::<PendingInput>(cx).is_none() {
22925            self.ime_transaction.take();
22926        }
22927    }
22928
22929    pub fn register_action_renderer(
22930        &mut self,
22931        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22932    ) -> Subscription {
22933        let id = self.next_editor_action_id.post_inc();
22934        self.editor_actions
22935            .borrow_mut()
22936            .insert(id, Box::new(listener));
22937
22938        let editor_actions = self.editor_actions.clone();
22939        Subscription::new(move || {
22940            editor_actions.borrow_mut().remove(&id);
22941        })
22942    }
22943
22944    pub fn register_action<A: Action>(
22945        &mut self,
22946        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22947    ) -> Subscription {
22948        let id = self.next_editor_action_id.post_inc();
22949        let listener = Arc::new(listener);
22950        self.editor_actions.borrow_mut().insert(
22951            id,
22952            Box::new(move |_, window, _| {
22953                let listener = listener.clone();
22954                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22955                    let action = action.downcast_ref().unwrap();
22956                    if phase == DispatchPhase::Bubble {
22957                        listener(action, window, cx)
22958                    }
22959                })
22960            }),
22961        );
22962
22963        let editor_actions = self.editor_actions.clone();
22964        Subscription::new(move || {
22965            editor_actions.borrow_mut().remove(&id);
22966        })
22967    }
22968
22969    pub fn file_header_size(&self) -> u32 {
22970        FILE_HEADER_HEIGHT
22971    }
22972
22973    pub fn restore(
22974        &mut self,
22975        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22976        window: &mut Window,
22977        cx: &mut Context<Self>,
22978    ) {
22979        self.buffer().update(cx, |multi_buffer, cx| {
22980            for (buffer_id, changes) in revert_changes {
22981                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22982                    buffer.update(cx, |buffer, cx| {
22983                        buffer.edit(
22984                            changes
22985                                .into_iter()
22986                                .map(|(range, text)| (range, text.to_string())),
22987                            None,
22988                            cx,
22989                        );
22990                    });
22991                }
22992            }
22993        });
22994        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22995            selections.refresh()
22996        });
22997    }
22998
22999    pub fn to_pixel_point(
23000        &mut self,
23001        source: multi_buffer::Anchor,
23002        editor_snapshot: &EditorSnapshot,
23003        window: &mut Window,
23004        cx: &App,
23005    ) -> Option<gpui::Point<Pixels>> {
23006        let source_point = source.to_display_point(editor_snapshot);
23007        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
23008    }
23009
23010    pub fn display_to_pixel_point(
23011        &mut self,
23012        source: DisplayPoint,
23013        editor_snapshot: &EditorSnapshot,
23014        window: &mut Window,
23015        cx: &App,
23016    ) -> Option<gpui::Point<Pixels>> {
23017        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
23018        let text_layout_details = self.text_layout_details(window);
23019        let scroll_top = text_layout_details
23020            .scroll_anchor
23021            .scroll_position(editor_snapshot)
23022            .y;
23023
23024        if source.row().as_f64() < scroll_top.floor() {
23025            return None;
23026        }
23027        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
23028        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
23029        Some(gpui::Point::new(source_x, source_y))
23030    }
23031
23032    pub fn has_visible_completions_menu(&self) -> bool {
23033        !self.edit_prediction_preview_is_active()
23034            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
23035                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
23036            })
23037    }
23038
23039    pub fn register_addon<T: Addon>(&mut self, instance: T) {
23040        if self.mode.is_minimap() {
23041            return;
23042        }
23043        self.addons
23044            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
23045    }
23046
23047    pub fn unregister_addon<T: Addon>(&mut self) {
23048        self.addons.remove(&std::any::TypeId::of::<T>());
23049    }
23050
23051    pub fn addon<T: Addon>(&self) -> Option<&T> {
23052        let type_id = std::any::TypeId::of::<T>();
23053        self.addons
23054            .get(&type_id)
23055            .and_then(|item| item.to_any().downcast_ref::<T>())
23056    }
23057
23058    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
23059        let type_id = std::any::TypeId::of::<T>();
23060        self.addons
23061            .get_mut(&type_id)
23062            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
23063    }
23064
23065    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
23066        let text_layout_details = self.text_layout_details(window);
23067        let style = &text_layout_details.editor_style;
23068        let font_id = window.text_system().resolve_font(&style.text.font());
23069        let font_size = style.text.font_size.to_pixels(window.rem_size());
23070        let line_height = style.text.line_height_in_pixels(window.rem_size());
23071        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
23072        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
23073
23074        CharacterDimensions {
23075            em_width,
23076            em_advance,
23077            line_height,
23078        }
23079    }
23080
23081    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
23082        self.load_diff_task.clone()
23083    }
23084
23085    fn read_metadata_from_db(
23086        &mut self,
23087        item_id: u64,
23088        workspace_id: WorkspaceId,
23089        window: &mut Window,
23090        cx: &mut Context<Editor>,
23091    ) {
23092        if self.buffer_kind(cx) == ItemBufferKind::Singleton
23093            && !self.mode.is_minimap()
23094            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
23095        {
23096            let buffer_snapshot = OnceCell::new();
23097
23098            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
23099                && !folds.is_empty()
23100            {
23101                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23102                self.fold_ranges(
23103                    folds
23104                        .into_iter()
23105                        .map(|(start, end)| {
23106                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23107                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23108                        })
23109                        .collect(),
23110                    false,
23111                    window,
23112                    cx,
23113                );
23114            }
23115
23116            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
23117                && !selections.is_empty()
23118            {
23119                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23120                // skip adding the initial selection to selection history
23121                self.selection_history.mode = SelectionHistoryMode::Skipping;
23122                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23123                    s.select_ranges(selections.into_iter().map(|(start, end)| {
23124                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23125                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23126                    }));
23127                });
23128                self.selection_history.mode = SelectionHistoryMode::Normal;
23129            };
23130        }
23131
23132        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
23133    }
23134
23135    fn update_lsp_data(
23136        &mut self,
23137        for_buffer: Option<BufferId>,
23138        window: &mut Window,
23139        cx: &mut Context<'_, Self>,
23140    ) {
23141        self.pull_diagnostics(for_buffer, window, cx);
23142        self.refresh_colors_for_visible_range(for_buffer, window, cx);
23143    }
23144
23145    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
23146        if self.ignore_lsp_data() {
23147            return;
23148        }
23149        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
23150            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
23151        }
23152    }
23153
23154    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
23155        if self.ignore_lsp_data() {
23156            return;
23157        }
23158
23159        if !self.registered_buffers.contains_key(&buffer_id)
23160            && let Some(project) = self.project.as_ref()
23161        {
23162            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
23163                project.update(cx, |project, cx| {
23164                    self.registered_buffers.insert(
23165                        buffer_id,
23166                        project.register_buffer_with_language_servers(&buffer, cx),
23167                    );
23168                });
23169            } else {
23170                self.registered_buffers.remove(&buffer_id);
23171            }
23172        }
23173    }
23174
23175    fn ignore_lsp_data(&self) -> bool {
23176        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
23177        // skip any LSP updates for it.
23178        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
23179    }
23180
23181    fn create_style(&self, cx: &App) -> EditorStyle {
23182        let settings = ThemeSettings::get_global(cx);
23183
23184        let mut text_style = match self.mode {
23185            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23186                color: cx.theme().colors().editor_foreground,
23187                font_family: settings.ui_font.family.clone(),
23188                font_features: settings.ui_font.features.clone(),
23189                font_fallbacks: settings.ui_font.fallbacks.clone(),
23190                font_size: rems(0.875).into(),
23191                font_weight: settings.ui_font.weight,
23192                line_height: relative(settings.buffer_line_height.value()),
23193                ..Default::default()
23194            },
23195            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23196                color: cx.theme().colors().editor_foreground,
23197                font_family: settings.buffer_font.family.clone(),
23198                font_features: settings.buffer_font.features.clone(),
23199                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23200                font_size: settings.buffer_font_size(cx).into(),
23201                font_weight: settings.buffer_font.weight,
23202                line_height: relative(settings.buffer_line_height.value()),
23203                ..Default::default()
23204            },
23205        };
23206        if let Some(text_style_refinement) = &self.text_style_refinement {
23207            text_style.refine(text_style_refinement)
23208        }
23209
23210        let background = match self.mode {
23211            EditorMode::SingleLine => cx.theme().system().transparent,
23212            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23213            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23214            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23215        };
23216
23217        EditorStyle {
23218            background,
23219            border: cx.theme().colors().border,
23220            local_player: cx.theme().players().local(),
23221            text: text_style,
23222            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23223            syntax: cx.theme().syntax().clone(),
23224            status: cx.theme().status().clone(),
23225            inlay_hints_style: make_inlay_hints_style(cx),
23226            edit_prediction_styles: make_suggestion_styles(cx),
23227            unnecessary_code_fade: settings.unnecessary_code_fade,
23228            show_underlines: self.diagnostics_enabled(),
23229        }
23230    }
23231}
23232
23233fn edit_for_markdown_paste<'a>(
23234    buffer: &MultiBufferSnapshot,
23235    range: Range<MultiBufferOffset>,
23236    to_insert: &'a str,
23237    url: Option<url::Url>,
23238) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
23239    if url.is_none() {
23240        return (range, Cow::Borrowed(to_insert));
23241    };
23242
23243    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
23244
23245    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
23246        Cow::Borrowed(to_insert)
23247    } else {
23248        Cow::Owned(format!("[{old_text}]({to_insert})"))
23249    };
23250    (range, new_text)
23251}
23252
23253fn process_completion_for_edit(
23254    completion: &Completion,
23255    intent: CompletionIntent,
23256    buffer: &Entity<Buffer>,
23257    cursor_position: &text::Anchor,
23258    cx: &mut Context<Editor>,
23259) -> CompletionEdit {
23260    let buffer = buffer.read(cx);
23261    let buffer_snapshot = buffer.snapshot();
23262    let (snippet, new_text) = if completion.is_snippet() {
23263        let mut snippet_source = completion.new_text.clone();
23264        // Workaround for typescript language server issues so that methods don't expand within
23265        // strings and functions with type expressions. The previous point is used because the query
23266        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
23267        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
23268        let previous_point = if previous_point.column > 0 {
23269            cursor_position.to_previous_offset(&buffer_snapshot)
23270        } else {
23271            cursor_position.to_offset(&buffer_snapshot)
23272        };
23273        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
23274            && scope.prefers_label_for_snippet_in_completion()
23275            && let Some(label) = completion.label()
23276            && matches!(
23277                completion.kind(),
23278                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
23279            )
23280        {
23281            snippet_source = label;
23282        }
23283        match Snippet::parse(&snippet_source).log_err() {
23284            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
23285            None => (None, completion.new_text.clone()),
23286        }
23287    } else {
23288        (None, completion.new_text.clone())
23289    };
23290
23291    let mut range_to_replace = {
23292        let replace_range = &completion.replace_range;
23293        if let CompletionSource::Lsp {
23294            insert_range: Some(insert_range),
23295            ..
23296        } = &completion.source
23297        {
23298            debug_assert_eq!(
23299                insert_range.start, replace_range.start,
23300                "insert_range and replace_range should start at the same position"
23301            );
23302            debug_assert!(
23303                insert_range
23304                    .start
23305                    .cmp(cursor_position, &buffer_snapshot)
23306                    .is_le(),
23307                "insert_range should start before or at cursor position"
23308            );
23309            debug_assert!(
23310                replace_range
23311                    .start
23312                    .cmp(cursor_position, &buffer_snapshot)
23313                    .is_le(),
23314                "replace_range should start before or at cursor position"
23315            );
23316
23317            let should_replace = match intent {
23318                CompletionIntent::CompleteWithInsert => false,
23319                CompletionIntent::CompleteWithReplace => true,
23320                CompletionIntent::Complete | CompletionIntent::Compose => {
23321                    let insert_mode =
23322                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
23323                            .completions
23324                            .lsp_insert_mode;
23325                    match insert_mode {
23326                        LspInsertMode::Insert => false,
23327                        LspInsertMode::Replace => true,
23328                        LspInsertMode::ReplaceSubsequence => {
23329                            let mut text_to_replace = buffer.chars_for_range(
23330                                buffer.anchor_before(replace_range.start)
23331                                    ..buffer.anchor_after(replace_range.end),
23332                            );
23333                            let mut current_needle = text_to_replace.next();
23334                            for haystack_ch in completion.label.text.chars() {
23335                                if let Some(needle_ch) = current_needle
23336                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
23337                                {
23338                                    current_needle = text_to_replace.next();
23339                                }
23340                            }
23341                            current_needle.is_none()
23342                        }
23343                        LspInsertMode::ReplaceSuffix => {
23344                            if replace_range
23345                                .end
23346                                .cmp(cursor_position, &buffer_snapshot)
23347                                .is_gt()
23348                            {
23349                                let range_after_cursor = *cursor_position..replace_range.end;
23350                                let text_after_cursor = buffer
23351                                    .text_for_range(
23352                                        buffer.anchor_before(range_after_cursor.start)
23353                                            ..buffer.anchor_after(range_after_cursor.end),
23354                                    )
23355                                    .collect::<String>()
23356                                    .to_ascii_lowercase();
23357                                completion
23358                                    .label
23359                                    .text
23360                                    .to_ascii_lowercase()
23361                                    .ends_with(&text_after_cursor)
23362                            } else {
23363                                true
23364                            }
23365                        }
23366                    }
23367                }
23368            };
23369
23370            if should_replace {
23371                replace_range.clone()
23372            } else {
23373                insert_range.clone()
23374            }
23375        } else {
23376            replace_range.clone()
23377        }
23378    };
23379
23380    if range_to_replace
23381        .end
23382        .cmp(cursor_position, &buffer_snapshot)
23383        .is_lt()
23384    {
23385        range_to_replace.end = *cursor_position;
23386    }
23387
23388    let replace_range = range_to_replace.to_offset(buffer);
23389    CompletionEdit {
23390        new_text,
23391        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
23392        snippet,
23393    }
23394}
23395
23396struct CompletionEdit {
23397    new_text: String,
23398    replace_range: Range<BufferOffset>,
23399    snippet: Option<Snippet>,
23400}
23401
23402fn insert_extra_newline_brackets(
23403    buffer: &MultiBufferSnapshot,
23404    range: Range<MultiBufferOffset>,
23405    language: &language::LanguageScope,
23406) -> bool {
23407    let leading_whitespace_len = buffer
23408        .reversed_chars_at(range.start)
23409        .take_while(|c| c.is_whitespace() && *c != '\n')
23410        .map(|c| c.len_utf8())
23411        .sum::<usize>();
23412    let trailing_whitespace_len = buffer
23413        .chars_at(range.end)
23414        .take_while(|c| c.is_whitespace() && *c != '\n')
23415        .map(|c| c.len_utf8())
23416        .sum::<usize>();
23417    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
23418
23419    language.brackets().any(|(pair, enabled)| {
23420        let pair_start = pair.start.trim_end();
23421        let pair_end = pair.end.trim_start();
23422
23423        enabled
23424            && pair.newline
23425            && buffer.contains_str_at(range.end, pair_end)
23426            && buffer.contains_str_at(
23427                range.start.saturating_sub_usize(pair_start.len()),
23428                pair_start,
23429            )
23430    })
23431}
23432
23433fn insert_extra_newline_tree_sitter(
23434    buffer: &MultiBufferSnapshot,
23435    range: Range<MultiBufferOffset>,
23436) -> bool {
23437    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
23438        [(buffer, range, _)] => (*buffer, range.clone()),
23439        _ => return false,
23440    };
23441    let pair = {
23442        let mut result: Option<BracketMatch<usize>> = None;
23443
23444        for pair in buffer
23445            .all_bracket_ranges(range.start.0..range.end.0)
23446            .filter(move |pair| {
23447                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
23448            })
23449        {
23450            let len = pair.close_range.end - pair.open_range.start;
23451
23452            if let Some(existing) = &result {
23453                let existing_len = existing.close_range.end - existing.open_range.start;
23454                if len > existing_len {
23455                    continue;
23456                }
23457            }
23458
23459            result = Some(pair);
23460        }
23461
23462        result
23463    };
23464    let Some(pair) = pair else {
23465        return false;
23466    };
23467    pair.newline_only
23468        && buffer
23469            .chars_for_range(pair.open_range.end..range.start.0)
23470            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
23471            .all(|c| c.is_whitespace() && c != '\n')
23472}
23473
23474fn update_uncommitted_diff_for_buffer(
23475    editor: Entity<Editor>,
23476    project: &Entity<Project>,
23477    buffers: impl IntoIterator<Item = Entity<Buffer>>,
23478    buffer: Entity<MultiBuffer>,
23479    cx: &mut App,
23480) -> Task<()> {
23481    let mut tasks = Vec::new();
23482    project.update(cx, |project, cx| {
23483        for buffer in buffers {
23484            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
23485                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
23486            }
23487        }
23488    });
23489    cx.spawn(async move |cx| {
23490        let diffs = future::join_all(tasks).await;
23491        if editor
23492            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
23493            .unwrap_or(false)
23494        {
23495            return;
23496        }
23497
23498        buffer
23499            .update(cx, |buffer, cx| {
23500                for diff in diffs.into_iter().flatten() {
23501                    buffer.add_diff(diff, cx);
23502                }
23503            })
23504            .ok();
23505    })
23506}
23507
23508fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
23509    let tab_size = tab_size.get() as usize;
23510    let mut width = offset;
23511
23512    for ch in text.chars() {
23513        width += if ch == '\t' {
23514            tab_size - (width % tab_size)
23515        } else {
23516            1
23517        };
23518    }
23519
23520    width - offset
23521}
23522
23523#[cfg(test)]
23524mod tests {
23525    use super::*;
23526
23527    #[test]
23528    fn test_string_size_with_expanded_tabs() {
23529        let nz = |val| NonZeroU32::new(val).unwrap();
23530        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
23531        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
23532        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
23533        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
23534        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
23535        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
23536        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
23537        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
23538    }
23539}
23540
23541/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
23542struct WordBreakingTokenizer<'a> {
23543    input: &'a str,
23544}
23545
23546impl<'a> WordBreakingTokenizer<'a> {
23547    fn new(input: &'a str) -> Self {
23548        Self { input }
23549    }
23550}
23551
23552fn is_char_ideographic(ch: char) -> bool {
23553    use unicode_script::Script::*;
23554    use unicode_script::UnicodeScript;
23555    matches!(ch.script(), Han | Tangut | Yi)
23556}
23557
23558fn is_grapheme_ideographic(text: &str) -> bool {
23559    text.chars().any(is_char_ideographic)
23560}
23561
23562fn is_grapheme_whitespace(text: &str) -> bool {
23563    text.chars().any(|x| x.is_whitespace())
23564}
23565
23566fn should_stay_with_preceding_ideograph(text: &str) -> bool {
23567    text.chars()
23568        .next()
23569        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
23570}
23571
23572#[derive(PartialEq, Eq, Debug, Clone, Copy)]
23573enum WordBreakToken<'a> {
23574    Word { token: &'a str, grapheme_len: usize },
23575    InlineWhitespace { token: &'a str, grapheme_len: usize },
23576    Newline,
23577}
23578
23579impl<'a> Iterator for WordBreakingTokenizer<'a> {
23580    /// Yields a span, the count of graphemes in the token, and whether it was
23581    /// whitespace. Note that it also breaks at word boundaries.
23582    type Item = WordBreakToken<'a>;
23583
23584    fn next(&mut self) -> Option<Self::Item> {
23585        use unicode_segmentation::UnicodeSegmentation;
23586        if self.input.is_empty() {
23587            return None;
23588        }
23589
23590        let mut iter = self.input.graphemes(true).peekable();
23591        let mut offset = 0;
23592        let mut grapheme_len = 0;
23593        if let Some(first_grapheme) = iter.next() {
23594            let is_newline = first_grapheme == "\n";
23595            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23596            offset += first_grapheme.len();
23597            grapheme_len += 1;
23598            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
23599                if let Some(grapheme) = iter.peek().copied()
23600                    && should_stay_with_preceding_ideograph(grapheme)
23601                {
23602                    offset += grapheme.len();
23603                    grapheme_len += 1;
23604                }
23605            } else {
23606                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23607                let mut next_word_bound = words.peek().copied();
23608                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23609                    next_word_bound = words.next();
23610                }
23611                while let Some(grapheme) = iter.peek().copied() {
23612                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23613                        break;
23614                    };
23615                    if is_grapheme_whitespace(grapheme) != is_whitespace
23616                        || (grapheme == "\n") != is_newline
23617                    {
23618                        break;
23619                    };
23620                    offset += grapheme.len();
23621                    grapheme_len += 1;
23622                    iter.next();
23623                }
23624            }
23625            let token = &self.input[..offset];
23626            self.input = &self.input[offset..];
23627            if token == "\n" {
23628                Some(WordBreakToken::Newline)
23629            } else if is_whitespace {
23630                Some(WordBreakToken::InlineWhitespace {
23631                    token,
23632                    grapheme_len,
23633                })
23634            } else {
23635                Some(WordBreakToken::Word {
23636                    token,
23637                    grapheme_len,
23638                })
23639            }
23640        } else {
23641            None
23642        }
23643    }
23644}
23645
23646#[test]
23647fn test_word_breaking_tokenizer() {
23648    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23649        ("", &[]),
23650        ("  ", &[whitespace("  ", 2)]),
23651        ("Ʒ", &[word("Ʒ", 1)]),
23652        ("Ǽ", &[word("Ǽ", 1)]),
23653        ("", &[word("", 1)]),
23654        ("⋑⋑", &[word("⋑⋑", 2)]),
23655        (
23656            "原理,进而",
23657            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23658        ),
23659        (
23660            "hello world",
23661            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23662        ),
23663        (
23664            "hello, world",
23665            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23666        ),
23667        (
23668            "  hello world",
23669            &[
23670                whitespace("  ", 2),
23671                word("hello", 5),
23672                whitespace(" ", 1),
23673                word("world", 5),
23674            ],
23675        ),
23676        (
23677            "这是什么 \n 钢笔",
23678            &[
23679                word("", 1),
23680                word("", 1),
23681                word("", 1),
23682                word("", 1),
23683                whitespace(" ", 1),
23684                newline(),
23685                whitespace(" ", 1),
23686                word("", 1),
23687                word("", 1),
23688            ],
23689        ),
23690        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23691    ];
23692
23693    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23694        WordBreakToken::Word {
23695            token,
23696            grapheme_len,
23697        }
23698    }
23699
23700    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23701        WordBreakToken::InlineWhitespace {
23702            token,
23703            grapheme_len,
23704        }
23705    }
23706
23707    fn newline() -> WordBreakToken<'static> {
23708        WordBreakToken::Newline
23709    }
23710
23711    for (input, result) in tests {
23712        assert_eq!(
23713            WordBreakingTokenizer::new(input)
23714                .collect::<Vec<_>>()
23715                .as_slice(),
23716            *result,
23717        );
23718    }
23719}
23720
23721fn wrap_with_prefix(
23722    first_line_prefix: String,
23723    subsequent_lines_prefix: String,
23724    unwrapped_text: String,
23725    wrap_column: usize,
23726    tab_size: NonZeroU32,
23727    preserve_existing_whitespace: bool,
23728) -> String {
23729    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23730    let subsequent_lines_prefix_len =
23731        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23732    let mut wrapped_text = String::new();
23733    let mut current_line = first_line_prefix;
23734    let mut is_first_line = true;
23735
23736    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23737    let mut current_line_len = first_line_prefix_len;
23738    let mut in_whitespace = false;
23739    for token in tokenizer {
23740        let have_preceding_whitespace = in_whitespace;
23741        match token {
23742            WordBreakToken::Word {
23743                token,
23744                grapheme_len,
23745            } => {
23746                in_whitespace = false;
23747                let current_prefix_len = if is_first_line {
23748                    first_line_prefix_len
23749                } else {
23750                    subsequent_lines_prefix_len
23751                };
23752                if current_line_len + grapheme_len > wrap_column
23753                    && current_line_len != current_prefix_len
23754                {
23755                    wrapped_text.push_str(current_line.trim_end());
23756                    wrapped_text.push('\n');
23757                    is_first_line = false;
23758                    current_line = subsequent_lines_prefix.clone();
23759                    current_line_len = subsequent_lines_prefix_len;
23760                }
23761                current_line.push_str(token);
23762                current_line_len += grapheme_len;
23763            }
23764            WordBreakToken::InlineWhitespace {
23765                mut token,
23766                mut grapheme_len,
23767            } => {
23768                in_whitespace = true;
23769                if have_preceding_whitespace && !preserve_existing_whitespace {
23770                    continue;
23771                }
23772                if !preserve_existing_whitespace {
23773                    // Keep a single whitespace grapheme as-is
23774                    if let Some(first) =
23775                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23776                    {
23777                        token = first;
23778                    } else {
23779                        token = " ";
23780                    }
23781                    grapheme_len = 1;
23782                }
23783                let current_prefix_len = if is_first_line {
23784                    first_line_prefix_len
23785                } else {
23786                    subsequent_lines_prefix_len
23787                };
23788                if current_line_len + grapheme_len > wrap_column {
23789                    wrapped_text.push_str(current_line.trim_end());
23790                    wrapped_text.push('\n');
23791                    is_first_line = false;
23792                    current_line = subsequent_lines_prefix.clone();
23793                    current_line_len = subsequent_lines_prefix_len;
23794                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23795                    current_line.push_str(token);
23796                    current_line_len += grapheme_len;
23797                }
23798            }
23799            WordBreakToken::Newline => {
23800                in_whitespace = true;
23801                let current_prefix_len = if is_first_line {
23802                    first_line_prefix_len
23803                } else {
23804                    subsequent_lines_prefix_len
23805                };
23806                if preserve_existing_whitespace {
23807                    wrapped_text.push_str(current_line.trim_end());
23808                    wrapped_text.push('\n');
23809                    is_first_line = false;
23810                    current_line = subsequent_lines_prefix.clone();
23811                    current_line_len = subsequent_lines_prefix_len;
23812                } else if have_preceding_whitespace {
23813                    continue;
23814                } else if current_line_len + 1 > wrap_column
23815                    && current_line_len != current_prefix_len
23816                {
23817                    wrapped_text.push_str(current_line.trim_end());
23818                    wrapped_text.push('\n');
23819                    is_first_line = false;
23820                    current_line = subsequent_lines_prefix.clone();
23821                    current_line_len = subsequent_lines_prefix_len;
23822                } else if current_line_len != current_prefix_len {
23823                    current_line.push(' ');
23824                    current_line_len += 1;
23825                }
23826            }
23827        }
23828    }
23829
23830    if !current_line.is_empty() {
23831        wrapped_text.push_str(&current_line);
23832    }
23833    wrapped_text
23834}
23835
23836#[test]
23837fn test_wrap_with_prefix() {
23838    assert_eq!(
23839        wrap_with_prefix(
23840            "# ".to_string(),
23841            "# ".to_string(),
23842            "abcdefg".to_string(),
23843            4,
23844            NonZeroU32::new(4).unwrap(),
23845            false,
23846        ),
23847        "# abcdefg"
23848    );
23849    assert_eq!(
23850        wrap_with_prefix(
23851            "".to_string(),
23852            "".to_string(),
23853            "\thello world".to_string(),
23854            8,
23855            NonZeroU32::new(4).unwrap(),
23856            false,
23857        ),
23858        "hello\nworld"
23859    );
23860    assert_eq!(
23861        wrap_with_prefix(
23862            "// ".to_string(),
23863            "// ".to_string(),
23864            "xx \nyy zz aa bb cc".to_string(),
23865            12,
23866            NonZeroU32::new(4).unwrap(),
23867            false,
23868        ),
23869        "// xx yy zz\n// aa bb cc"
23870    );
23871    assert_eq!(
23872        wrap_with_prefix(
23873            String::new(),
23874            String::new(),
23875            "这是什么 \n 钢笔".to_string(),
23876            3,
23877            NonZeroU32::new(4).unwrap(),
23878            false,
23879        ),
23880        "这是什\n么 钢\n"
23881    );
23882    assert_eq!(
23883        wrap_with_prefix(
23884            String::new(),
23885            String::new(),
23886            format!("foo{}bar", '\u{2009}'), // thin space
23887            80,
23888            NonZeroU32::new(4).unwrap(),
23889            false,
23890        ),
23891        format!("foo{}bar", '\u{2009}')
23892    );
23893}
23894
23895pub trait CollaborationHub {
23896    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23897    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23898    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23899}
23900
23901impl CollaborationHub for Entity<Project> {
23902    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23903        self.read(cx).collaborators()
23904    }
23905
23906    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23907        self.read(cx).user_store().read(cx).participant_indices()
23908    }
23909
23910    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23911        let this = self.read(cx);
23912        let user_ids = this.collaborators().values().map(|c| c.user_id);
23913        this.user_store().read(cx).participant_names(user_ids, cx)
23914    }
23915}
23916
23917pub trait SemanticsProvider {
23918    fn hover(
23919        &self,
23920        buffer: &Entity<Buffer>,
23921        position: text::Anchor,
23922        cx: &mut App,
23923    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23924
23925    fn inline_values(
23926        &self,
23927        buffer_handle: Entity<Buffer>,
23928        range: Range<text::Anchor>,
23929        cx: &mut App,
23930    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23931
23932    fn applicable_inlay_chunks(
23933        &self,
23934        buffer: &Entity<Buffer>,
23935        ranges: &[Range<text::Anchor>],
23936        cx: &mut App,
23937    ) -> Vec<Range<BufferRow>>;
23938
23939    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23940
23941    fn inlay_hints(
23942        &self,
23943        invalidate: InvalidationStrategy,
23944        buffer: Entity<Buffer>,
23945        ranges: Vec<Range<text::Anchor>>,
23946        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23947        cx: &mut App,
23948    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23949
23950    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23951
23952    fn document_highlights(
23953        &self,
23954        buffer: &Entity<Buffer>,
23955        position: text::Anchor,
23956        cx: &mut App,
23957    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23958
23959    fn definitions(
23960        &self,
23961        buffer: &Entity<Buffer>,
23962        position: text::Anchor,
23963        kind: GotoDefinitionKind,
23964        cx: &mut App,
23965    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23966
23967    fn range_for_rename(
23968        &self,
23969        buffer: &Entity<Buffer>,
23970        position: text::Anchor,
23971        cx: &mut App,
23972    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23973
23974    fn perform_rename(
23975        &self,
23976        buffer: &Entity<Buffer>,
23977        position: text::Anchor,
23978        new_name: String,
23979        cx: &mut App,
23980    ) -> Option<Task<Result<ProjectTransaction>>>;
23981}
23982
23983pub trait CompletionProvider {
23984    fn completions(
23985        &self,
23986        excerpt_id: ExcerptId,
23987        buffer: &Entity<Buffer>,
23988        buffer_position: text::Anchor,
23989        trigger: CompletionContext,
23990        window: &mut Window,
23991        cx: &mut Context<Editor>,
23992    ) -> Task<Result<Vec<CompletionResponse>>>;
23993
23994    fn resolve_completions(
23995        &self,
23996        _buffer: Entity<Buffer>,
23997        _completion_indices: Vec<usize>,
23998        _completions: Rc<RefCell<Box<[Completion]>>>,
23999        _cx: &mut Context<Editor>,
24000    ) -> Task<Result<bool>> {
24001        Task::ready(Ok(false))
24002    }
24003
24004    fn apply_additional_edits_for_completion(
24005        &self,
24006        _buffer: Entity<Buffer>,
24007        _completions: Rc<RefCell<Box<[Completion]>>>,
24008        _completion_index: usize,
24009        _push_to_history: bool,
24010        _cx: &mut Context<Editor>,
24011    ) -> Task<Result<Option<language::Transaction>>> {
24012        Task::ready(Ok(None))
24013    }
24014
24015    fn is_completion_trigger(
24016        &self,
24017        buffer: &Entity<Buffer>,
24018        position: language::Anchor,
24019        text: &str,
24020        trigger_in_words: bool,
24021        cx: &mut Context<Editor>,
24022    ) -> bool;
24023
24024    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
24025
24026    fn sort_completions(&self) -> bool {
24027        true
24028    }
24029
24030    fn filter_completions(&self) -> bool {
24031        true
24032    }
24033
24034    fn show_snippets(&self) -> bool {
24035        false
24036    }
24037}
24038
24039pub trait CodeActionProvider {
24040    fn id(&self) -> Arc<str>;
24041
24042    fn code_actions(
24043        &self,
24044        buffer: &Entity<Buffer>,
24045        range: Range<text::Anchor>,
24046        window: &mut Window,
24047        cx: &mut App,
24048    ) -> Task<Result<Vec<CodeAction>>>;
24049
24050    fn apply_code_action(
24051        &self,
24052        buffer_handle: Entity<Buffer>,
24053        action: CodeAction,
24054        excerpt_id: ExcerptId,
24055        push_to_history: bool,
24056        window: &mut Window,
24057        cx: &mut App,
24058    ) -> Task<Result<ProjectTransaction>>;
24059}
24060
24061impl CodeActionProvider for Entity<Project> {
24062    fn id(&self) -> Arc<str> {
24063        "project".into()
24064    }
24065
24066    fn code_actions(
24067        &self,
24068        buffer: &Entity<Buffer>,
24069        range: Range<text::Anchor>,
24070        _window: &mut Window,
24071        cx: &mut App,
24072    ) -> Task<Result<Vec<CodeAction>>> {
24073        self.update(cx, |project, cx| {
24074            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
24075            let code_actions = project.code_actions(buffer, range, None, cx);
24076            cx.background_spawn(async move {
24077                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
24078                Ok(code_lens_actions
24079                    .context("code lens fetch")?
24080                    .into_iter()
24081                    .flatten()
24082                    .chain(
24083                        code_actions
24084                            .context("code action fetch")?
24085                            .into_iter()
24086                            .flatten(),
24087                    )
24088                    .collect())
24089            })
24090        })
24091    }
24092
24093    fn apply_code_action(
24094        &self,
24095        buffer_handle: Entity<Buffer>,
24096        action: CodeAction,
24097        _excerpt_id: ExcerptId,
24098        push_to_history: bool,
24099        _window: &mut Window,
24100        cx: &mut App,
24101    ) -> Task<Result<ProjectTransaction>> {
24102        self.update(cx, |project, cx| {
24103            project.apply_code_action(buffer_handle, action, push_to_history, cx)
24104        })
24105    }
24106}
24107
24108fn snippet_completions(
24109    project: &Project,
24110    buffer: &Entity<Buffer>,
24111    buffer_anchor: text::Anchor,
24112    classifier: CharClassifier,
24113    cx: &mut App,
24114) -> Task<Result<CompletionResponse>> {
24115    let languages = buffer.read(cx).languages_at(buffer_anchor);
24116    let snippet_store = project.snippets().read(cx);
24117
24118    let scopes: Vec<_> = languages
24119        .iter()
24120        .filter_map(|language| {
24121            let language_name = language.lsp_id();
24122            let snippets = snippet_store.snippets_for(Some(language_name), cx);
24123
24124            if snippets.is_empty() {
24125                None
24126            } else {
24127                Some((language.default_scope(), snippets))
24128            }
24129        })
24130        .collect();
24131
24132    if scopes.is_empty() {
24133        return Task::ready(Ok(CompletionResponse {
24134            completions: vec![],
24135            display_options: CompletionDisplayOptions::default(),
24136            is_incomplete: false,
24137        }));
24138    }
24139
24140    let snapshot = buffer.read(cx).text_snapshot();
24141    let executor = cx.background_executor().clone();
24142
24143    cx.background_spawn(async move {
24144        let is_word_char = |c| classifier.is_word(c);
24145
24146        let mut is_incomplete = false;
24147        let mut completions: Vec<Completion> = Vec::new();
24148
24149        const MAX_PREFIX_LEN: usize = 128;
24150        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
24151        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
24152        let window_start = snapshot.clip_offset(window_start, Bias::Left);
24153
24154        let max_buffer_window: String = snapshot
24155            .text_for_range(window_start..buffer_offset)
24156            .collect();
24157
24158        if max_buffer_window.is_empty() {
24159            return Ok(CompletionResponse {
24160                completions: vec![],
24161                display_options: CompletionDisplayOptions::default(),
24162                is_incomplete: true,
24163            });
24164        }
24165
24166        for (_scope, snippets) in scopes.into_iter() {
24167            // Sort snippets by word count to match longer snippet prefixes first.
24168            let mut sorted_snippet_candidates = snippets
24169                .iter()
24170                .enumerate()
24171                .flat_map(|(snippet_ix, snippet)| {
24172                    snippet
24173                        .prefix
24174                        .iter()
24175                        .enumerate()
24176                        .map(move |(prefix_ix, prefix)| {
24177                            let word_count =
24178                                snippet_candidate_suffixes(prefix, is_word_char).count();
24179                            ((snippet_ix, prefix_ix), prefix, word_count)
24180                        })
24181                })
24182                .collect_vec();
24183            sorted_snippet_candidates
24184                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
24185
24186            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
24187
24188            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
24189                .take(
24190                    sorted_snippet_candidates
24191                        .first()
24192                        .map(|(_, _, word_count)| *word_count)
24193                        .unwrap_or_default(),
24194                )
24195                .collect_vec();
24196
24197            const MAX_RESULTS: usize = 100;
24198            // Each match also remembers how many characters from the buffer it consumed
24199            let mut matches: Vec<(StringMatch, usize)> = vec![];
24200
24201            let mut snippet_list_cutoff_index = 0;
24202            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
24203                let word_count = buffer_index + 1;
24204                // Increase `snippet_list_cutoff_index` until we have all of the
24205                // snippets with sufficiently many words.
24206                while sorted_snippet_candidates
24207                    .get(snippet_list_cutoff_index)
24208                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
24209                        *snippet_word_count >= word_count
24210                    })
24211                {
24212                    snippet_list_cutoff_index += 1;
24213                }
24214
24215                // Take only the candidates with at least `word_count` many words
24216                let snippet_candidates_at_word_len =
24217                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
24218
24219                let candidates = snippet_candidates_at_word_len
24220                    .iter()
24221                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
24222                    .enumerate() // index in `sorted_snippet_candidates`
24223                    // First char must match
24224                    .filter(|(_ix, prefix)| {
24225                        itertools::equal(
24226                            prefix
24227                                .chars()
24228                                .next()
24229                                .into_iter()
24230                                .flat_map(|c| c.to_lowercase()),
24231                            buffer_window
24232                                .chars()
24233                                .next()
24234                                .into_iter()
24235                                .flat_map(|c| c.to_lowercase()),
24236                        )
24237                    })
24238                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
24239                    .collect::<Vec<StringMatchCandidate>>();
24240
24241                matches.extend(
24242                    fuzzy::match_strings(
24243                        &candidates,
24244                        &buffer_window,
24245                        buffer_window.chars().any(|c| c.is_uppercase()),
24246                        true,
24247                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
24248                        &Default::default(),
24249                        executor.clone(),
24250                    )
24251                    .await
24252                    .into_iter()
24253                    .map(|string_match| (string_match, buffer_window.len())),
24254                );
24255
24256                if matches.len() >= MAX_RESULTS {
24257                    break;
24258                }
24259            }
24260
24261            let to_lsp = |point: &text::Anchor| {
24262                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
24263                point_to_lsp(end)
24264            };
24265            let lsp_end = to_lsp(&buffer_anchor);
24266
24267            if matches.len() >= MAX_RESULTS {
24268                is_incomplete = true;
24269            }
24270
24271            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
24272                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
24273                    sorted_snippet_candidates[string_match.candidate_id];
24274                let snippet = &snippets[snippet_index];
24275                let start = buffer_offset - buffer_window_len;
24276                let start = snapshot.anchor_before(start);
24277                let range = start..buffer_anchor;
24278                let lsp_start = to_lsp(&start);
24279                let lsp_range = lsp::Range {
24280                    start: lsp_start,
24281                    end: lsp_end,
24282                };
24283                Completion {
24284                    replace_range: range,
24285                    new_text: snippet.body.clone(),
24286                    source: CompletionSource::Lsp {
24287                        insert_range: None,
24288                        server_id: LanguageServerId(usize::MAX),
24289                        resolved: true,
24290                        lsp_completion: Box::new(lsp::CompletionItem {
24291                            label: snippet.prefix.first().unwrap().clone(),
24292                            kind: Some(CompletionItemKind::SNIPPET),
24293                            label_details: snippet.description.as_ref().map(|description| {
24294                                lsp::CompletionItemLabelDetails {
24295                                    detail: Some(description.clone()),
24296                                    description: None,
24297                                }
24298                            }),
24299                            insert_text_format: Some(InsertTextFormat::SNIPPET),
24300                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
24301                                lsp::InsertReplaceEdit {
24302                                    new_text: snippet.body.clone(),
24303                                    insert: lsp_range,
24304                                    replace: lsp_range,
24305                                },
24306                            )),
24307                            filter_text: Some(snippet.body.clone()),
24308                            sort_text: Some(char::MAX.to_string()),
24309                            ..lsp::CompletionItem::default()
24310                        }),
24311                        lsp_defaults: None,
24312                    },
24313                    label: CodeLabel {
24314                        text: matching_prefix.clone(),
24315                        runs: Vec::new(),
24316                        filter_range: 0..matching_prefix.len(),
24317                    },
24318                    icon_path: None,
24319                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
24320                        single_line: snippet.name.clone().into(),
24321                        plain_text: snippet
24322                            .description
24323                            .clone()
24324                            .map(|description| description.into()),
24325                    }),
24326                    insert_text_mode: None,
24327                    confirm: None,
24328                    match_start: Some(start),
24329                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
24330                }
24331            }));
24332        }
24333
24334        Ok(CompletionResponse {
24335            completions,
24336            display_options: CompletionDisplayOptions::default(),
24337            is_incomplete,
24338        })
24339    })
24340}
24341
24342impl CompletionProvider for Entity<Project> {
24343    fn completions(
24344        &self,
24345        _excerpt_id: ExcerptId,
24346        buffer: &Entity<Buffer>,
24347        buffer_position: text::Anchor,
24348        options: CompletionContext,
24349        _window: &mut Window,
24350        cx: &mut Context<Editor>,
24351    ) -> Task<Result<Vec<CompletionResponse>>> {
24352        self.update(cx, |project, cx| {
24353            let task = project.completions(buffer, buffer_position, options, cx);
24354            cx.background_spawn(task)
24355        })
24356    }
24357
24358    fn resolve_completions(
24359        &self,
24360        buffer: Entity<Buffer>,
24361        completion_indices: Vec<usize>,
24362        completions: Rc<RefCell<Box<[Completion]>>>,
24363        cx: &mut Context<Editor>,
24364    ) -> Task<Result<bool>> {
24365        self.update(cx, |project, cx| {
24366            project.lsp_store().update(cx, |lsp_store, cx| {
24367                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
24368            })
24369        })
24370    }
24371
24372    fn apply_additional_edits_for_completion(
24373        &self,
24374        buffer: Entity<Buffer>,
24375        completions: Rc<RefCell<Box<[Completion]>>>,
24376        completion_index: usize,
24377        push_to_history: bool,
24378        cx: &mut Context<Editor>,
24379    ) -> Task<Result<Option<language::Transaction>>> {
24380        self.update(cx, |project, cx| {
24381            project.lsp_store().update(cx, |lsp_store, cx| {
24382                lsp_store.apply_additional_edits_for_completion(
24383                    buffer,
24384                    completions,
24385                    completion_index,
24386                    push_to_history,
24387                    cx,
24388                )
24389            })
24390        })
24391    }
24392
24393    fn is_completion_trigger(
24394        &self,
24395        buffer: &Entity<Buffer>,
24396        position: language::Anchor,
24397        text: &str,
24398        trigger_in_words: bool,
24399        cx: &mut Context<Editor>,
24400    ) -> bool {
24401        let mut chars = text.chars();
24402        let char = if let Some(char) = chars.next() {
24403            char
24404        } else {
24405            return false;
24406        };
24407        if chars.next().is_some() {
24408            return false;
24409        }
24410
24411        let buffer = buffer.read(cx);
24412        let snapshot = buffer.snapshot();
24413        let classifier = snapshot
24414            .char_classifier_at(position)
24415            .scope_context(Some(CharScopeContext::Completion));
24416        if trigger_in_words && classifier.is_word(char) {
24417            return true;
24418        }
24419
24420        buffer.completion_triggers().contains(text)
24421    }
24422
24423    fn show_snippets(&self) -> bool {
24424        true
24425    }
24426}
24427
24428impl SemanticsProvider for Entity<Project> {
24429    fn hover(
24430        &self,
24431        buffer: &Entity<Buffer>,
24432        position: text::Anchor,
24433        cx: &mut App,
24434    ) -> Option<Task<Option<Vec<project::Hover>>>> {
24435        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
24436    }
24437
24438    fn document_highlights(
24439        &self,
24440        buffer: &Entity<Buffer>,
24441        position: text::Anchor,
24442        cx: &mut App,
24443    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
24444        Some(self.update(cx, |project, cx| {
24445            project.document_highlights(buffer, position, cx)
24446        }))
24447    }
24448
24449    fn definitions(
24450        &self,
24451        buffer: &Entity<Buffer>,
24452        position: text::Anchor,
24453        kind: GotoDefinitionKind,
24454        cx: &mut App,
24455    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
24456        Some(self.update(cx, |project, cx| match kind {
24457            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
24458            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
24459            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
24460            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
24461        }))
24462    }
24463
24464    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
24465        self.update(cx, |project, cx| {
24466            if project
24467                .active_debug_session(cx)
24468                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
24469            {
24470                return true;
24471            }
24472
24473            buffer.update(cx, |buffer, cx| {
24474                project.any_language_server_supports_inlay_hints(buffer, cx)
24475            })
24476        })
24477    }
24478
24479    fn inline_values(
24480        &self,
24481        buffer_handle: Entity<Buffer>,
24482        range: Range<text::Anchor>,
24483        cx: &mut App,
24484    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
24485        self.update(cx, |project, cx| {
24486            let (session, active_stack_frame) = project.active_debug_session(cx)?;
24487
24488            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
24489        })
24490    }
24491
24492    fn applicable_inlay_chunks(
24493        &self,
24494        buffer: &Entity<Buffer>,
24495        ranges: &[Range<text::Anchor>],
24496        cx: &mut App,
24497    ) -> Vec<Range<BufferRow>> {
24498        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24499            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
24500        })
24501    }
24502
24503    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
24504        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
24505            lsp_store.invalidate_inlay_hints(for_buffers)
24506        });
24507    }
24508
24509    fn inlay_hints(
24510        &self,
24511        invalidate: InvalidationStrategy,
24512        buffer: Entity<Buffer>,
24513        ranges: Vec<Range<text::Anchor>>,
24514        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24515        cx: &mut App,
24516    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
24517        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24518            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
24519        }))
24520    }
24521
24522    fn range_for_rename(
24523        &self,
24524        buffer: &Entity<Buffer>,
24525        position: text::Anchor,
24526        cx: &mut App,
24527    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
24528        Some(self.update(cx, |project, cx| {
24529            let buffer = buffer.clone();
24530            let task = project.prepare_rename(buffer.clone(), position, cx);
24531            cx.spawn(async move |_, cx| {
24532                Ok(match task.await? {
24533                    PrepareRenameResponse::Success(range) => Some(range),
24534                    PrepareRenameResponse::InvalidPosition => None,
24535                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
24536                        // Fallback on using TreeSitter info to determine identifier range
24537                        buffer.read_with(cx, |buffer, _| {
24538                            let snapshot = buffer.snapshot();
24539                            let (range, kind) = snapshot.surrounding_word(position, None);
24540                            if kind != Some(CharKind::Word) {
24541                                return None;
24542                            }
24543                            Some(
24544                                snapshot.anchor_before(range.start)
24545                                    ..snapshot.anchor_after(range.end),
24546                            )
24547                        })?
24548                    }
24549                })
24550            })
24551        }))
24552    }
24553
24554    fn perform_rename(
24555        &self,
24556        buffer: &Entity<Buffer>,
24557        position: text::Anchor,
24558        new_name: String,
24559        cx: &mut App,
24560    ) -> Option<Task<Result<ProjectTransaction>>> {
24561        Some(self.update(cx, |project, cx| {
24562            project.perform_rename(buffer.clone(), position, new_name, cx)
24563        }))
24564    }
24565}
24566
24567fn consume_contiguous_rows(
24568    contiguous_row_selections: &mut Vec<Selection<Point>>,
24569    selection: &Selection<Point>,
24570    display_map: &DisplaySnapshot,
24571    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
24572) -> (MultiBufferRow, MultiBufferRow) {
24573    contiguous_row_selections.push(selection.clone());
24574    let start_row = starting_row(selection, display_map);
24575    let mut end_row = ending_row(selection, display_map);
24576
24577    while let Some(next_selection) = selections.peek() {
24578        if next_selection.start.row <= end_row.0 {
24579            end_row = ending_row(next_selection, display_map);
24580            contiguous_row_selections.push(selections.next().unwrap().clone());
24581        } else {
24582            break;
24583        }
24584    }
24585    (start_row, end_row)
24586}
24587
24588fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24589    if selection.start.column > 0 {
24590        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
24591    } else {
24592        MultiBufferRow(selection.start.row)
24593    }
24594}
24595
24596fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24597    if next_selection.end.column > 0 || next_selection.is_empty() {
24598        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
24599    } else {
24600        MultiBufferRow(next_selection.end.row)
24601    }
24602}
24603
24604impl EditorSnapshot {
24605    pub fn remote_selections_in_range<'a>(
24606        &'a self,
24607        range: &'a Range<Anchor>,
24608        collaboration_hub: &dyn CollaborationHub,
24609        cx: &'a App,
24610    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24611        let participant_names = collaboration_hub.user_names(cx);
24612        let participant_indices = collaboration_hub.user_participant_indices(cx);
24613        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24614        let collaborators_by_replica_id = collaborators_by_peer_id
24615            .values()
24616            .map(|collaborator| (collaborator.replica_id, collaborator))
24617            .collect::<HashMap<_, _>>();
24618        self.buffer_snapshot()
24619            .selections_in_range(range, false)
24620            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24621                if replica_id == ReplicaId::AGENT {
24622                    Some(RemoteSelection {
24623                        replica_id,
24624                        selection,
24625                        cursor_shape,
24626                        line_mode,
24627                        collaborator_id: CollaboratorId::Agent,
24628                        user_name: Some("Agent".into()),
24629                        color: cx.theme().players().agent(),
24630                    })
24631                } else {
24632                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24633                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24634                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24635                    Some(RemoteSelection {
24636                        replica_id,
24637                        selection,
24638                        cursor_shape,
24639                        line_mode,
24640                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24641                        user_name,
24642                        color: if let Some(index) = participant_index {
24643                            cx.theme().players().color_for_participant(index.0)
24644                        } else {
24645                            cx.theme().players().absent()
24646                        },
24647                    })
24648                }
24649            })
24650    }
24651
24652    pub fn hunks_for_ranges(
24653        &self,
24654        ranges: impl IntoIterator<Item = Range<Point>>,
24655    ) -> Vec<MultiBufferDiffHunk> {
24656        let mut hunks = Vec::new();
24657        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24658            HashMap::default();
24659        for query_range in ranges {
24660            let query_rows =
24661                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24662            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24663                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24664            ) {
24665                // Include deleted hunks that are adjacent to the query range, because
24666                // otherwise they would be missed.
24667                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24668                if hunk.status().is_deleted() {
24669                    intersects_range |= hunk.row_range.start == query_rows.end;
24670                    intersects_range |= hunk.row_range.end == query_rows.start;
24671                }
24672                if intersects_range {
24673                    if !processed_buffer_rows
24674                        .entry(hunk.buffer_id)
24675                        .or_default()
24676                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24677                    {
24678                        continue;
24679                    }
24680                    hunks.push(hunk);
24681                }
24682            }
24683        }
24684
24685        hunks
24686    }
24687
24688    fn display_diff_hunks_for_rows<'a>(
24689        &'a self,
24690        display_rows: Range<DisplayRow>,
24691        folded_buffers: &'a HashSet<BufferId>,
24692    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24693        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24694        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24695
24696        self.buffer_snapshot()
24697            .diff_hunks_in_range(buffer_start..buffer_end)
24698            .filter_map(|hunk| {
24699                if folded_buffers.contains(&hunk.buffer_id) {
24700                    return None;
24701                }
24702
24703                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24704                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24705
24706                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24707                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24708
24709                let display_hunk = if hunk_display_start.column() != 0 {
24710                    DisplayDiffHunk::Folded {
24711                        display_row: hunk_display_start.row(),
24712                    }
24713                } else {
24714                    let mut end_row = hunk_display_end.row();
24715                    if hunk_display_end.column() > 0 {
24716                        end_row.0 += 1;
24717                    }
24718                    let is_created_file = hunk.is_created_file();
24719
24720                    DisplayDiffHunk::Unfolded {
24721                        status: hunk.status(),
24722                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24723                            ..hunk.diff_base_byte_range.end.0,
24724                        word_diffs: hunk.word_diffs,
24725                        display_row_range: hunk_display_start.row()..end_row,
24726                        multi_buffer_range: Anchor::range_in_buffer(
24727                            hunk.excerpt_id,
24728                            hunk.buffer_range,
24729                        ),
24730                        is_created_file,
24731                    }
24732                };
24733
24734                Some(display_hunk)
24735            })
24736    }
24737
24738    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24739        self.display_snapshot
24740            .buffer_snapshot()
24741            .language_at(position)
24742    }
24743
24744    pub fn is_focused(&self) -> bool {
24745        self.is_focused
24746    }
24747
24748    pub fn placeholder_text(&self) -> Option<String> {
24749        self.placeholder_display_snapshot
24750            .as_ref()
24751            .map(|display_map| display_map.text())
24752    }
24753
24754    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24755        self.scroll_anchor.scroll_position(&self.display_snapshot)
24756    }
24757
24758    pub fn gutter_dimensions(
24759        &self,
24760        font_id: FontId,
24761        font_size: Pixels,
24762        style: &EditorStyle,
24763        window: &mut Window,
24764        cx: &App,
24765    ) -> GutterDimensions {
24766        if self.show_gutter
24767            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
24768            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
24769        {
24770            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24771                matches!(
24772                    ProjectSettings::get_global(cx).git.git_gutter,
24773                    GitGutterSetting::TrackedFiles
24774                )
24775            });
24776            let gutter_settings = EditorSettings::get_global(cx).gutter;
24777            let show_line_numbers = self
24778                .show_line_numbers
24779                .unwrap_or(gutter_settings.line_numbers);
24780            let line_gutter_width = if show_line_numbers {
24781                // Avoid flicker-like gutter resizes when the line number gains another digit by
24782                // only resizing the gutter on files with > 10**min_line_number_digits lines.
24783                let min_width_for_number_on_gutter =
24784                    ch_advance * gutter_settings.min_line_number_digits as f32;
24785                self.max_line_number_width(style, window)
24786                    .max(min_width_for_number_on_gutter)
24787            } else {
24788                0.0.into()
24789            };
24790
24791            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24792            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24793
24794            let git_blame_entries_width =
24795                self.git_blame_gutter_max_author_length
24796                    .map(|max_author_length| {
24797                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24798                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24799
24800                        /// The number of characters to dedicate to gaps and margins.
24801                        const SPACING_WIDTH: usize = 4;
24802
24803                        let max_char_count = max_author_length.min(renderer.max_author_length())
24804                            + ::git::SHORT_SHA_LENGTH
24805                            + MAX_RELATIVE_TIMESTAMP.len()
24806                            + SPACING_WIDTH;
24807
24808                        ch_advance * max_char_count
24809                    });
24810
24811            let is_singleton = self.buffer_snapshot().is_singleton();
24812
24813            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24814            left_padding += if !is_singleton {
24815                ch_width * 4.0
24816            } else if show_runnables || show_breakpoints {
24817                ch_width * 3.0
24818            } else if show_git_gutter && show_line_numbers {
24819                ch_width * 2.0
24820            } else if show_git_gutter || show_line_numbers {
24821                ch_width
24822            } else {
24823                px(0.)
24824            };
24825
24826            let shows_folds = is_singleton && gutter_settings.folds;
24827
24828            let right_padding = if shows_folds && show_line_numbers {
24829                ch_width * 4.0
24830            } else if shows_folds || (!is_singleton && show_line_numbers) {
24831                ch_width * 3.0
24832            } else if show_line_numbers {
24833                ch_width
24834            } else {
24835                px(0.)
24836            };
24837
24838            GutterDimensions {
24839                left_padding,
24840                right_padding,
24841                width: line_gutter_width + left_padding + right_padding,
24842                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24843                git_blame_entries_width,
24844            }
24845        } else if self.offset_content {
24846            GutterDimensions::default_with_margin(font_id, font_size, cx)
24847        } else {
24848            GutterDimensions::default()
24849        }
24850    }
24851
24852    pub fn render_crease_toggle(
24853        &self,
24854        buffer_row: MultiBufferRow,
24855        row_contains_cursor: bool,
24856        editor: Entity<Editor>,
24857        window: &mut Window,
24858        cx: &mut App,
24859    ) -> Option<AnyElement> {
24860        let folded = self.is_line_folded(buffer_row);
24861        let mut is_foldable = false;
24862
24863        if let Some(crease) = self
24864            .crease_snapshot
24865            .query_row(buffer_row, self.buffer_snapshot())
24866        {
24867            is_foldable = true;
24868            match crease {
24869                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24870                    if let Some(render_toggle) = render_toggle {
24871                        let toggle_callback =
24872                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24873                                if folded {
24874                                    editor.update(cx, |editor, cx| {
24875                                        editor.fold_at(buffer_row, window, cx)
24876                                    });
24877                                } else {
24878                                    editor.update(cx, |editor, cx| {
24879                                        editor.unfold_at(buffer_row, window, cx)
24880                                    });
24881                                }
24882                            });
24883                        return Some((render_toggle)(
24884                            buffer_row,
24885                            folded,
24886                            toggle_callback,
24887                            window,
24888                            cx,
24889                        ));
24890                    }
24891                }
24892            }
24893        }
24894
24895        is_foldable |= self.starts_indent(buffer_row);
24896
24897        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24898            Some(
24899                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24900                    .toggle_state(folded)
24901                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24902                        if folded {
24903                            this.unfold_at(buffer_row, window, cx);
24904                        } else {
24905                            this.fold_at(buffer_row, window, cx);
24906                        }
24907                    }))
24908                    .into_any_element(),
24909            )
24910        } else {
24911            None
24912        }
24913    }
24914
24915    pub fn render_crease_trailer(
24916        &self,
24917        buffer_row: MultiBufferRow,
24918        window: &mut Window,
24919        cx: &mut App,
24920    ) -> Option<AnyElement> {
24921        let folded = self.is_line_folded(buffer_row);
24922        if let Crease::Inline { render_trailer, .. } = self
24923            .crease_snapshot
24924            .query_row(buffer_row, self.buffer_snapshot())?
24925        {
24926            let render_trailer = render_trailer.as_ref()?;
24927            Some(render_trailer(buffer_row, folded, window, cx))
24928        } else {
24929            None
24930        }
24931    }
24932
24933    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
24934        let digit_count = self.widest_line_number().ilog10() + 1;
24935        column_pixels(style, digit_count as usize, window)
24936    }
24937}
24938
24939pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
24940    let font_size = style.text.font_size.to_pixels(window.rem_size());
24941    let layout = window.text_system().shape_line(
24942        SharedString::from(" ".repeat(column)),
24943        font_size,
24944        &[TextRun {
24945            len: column,
24946            font: style.text.font(),
24947            color: Hsla::default(),
24948            ..Default::default()
24949        }],
24950        None,
24951    );
24952
24953    layout.width
24954}
24955
24956impl Deref for EditorSnapshot {
24957    type Target = DisplaySnapshot;
24958
24959    fn deref(&self) -> &Self::Target {
24960        &self.display_snapshot
24961    }
24962}
24963
24964#[derive(Clone, Debug, PartialEq, Eq)]
24965pub enum EditorEvent {
24966    InputIgnored {
24967        text: Arc<str>,
24968    },
24969    InputHandled {
24970        utf16_range_to_replace: Option<Range<isize>>,
24971        text: Arc<str>,
24972    },
24973    ExcerptsAdded {
24974        buffer: Entity<Buffer>,
24975        predecessor: ExcerptId,
24976        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24977    },
24978    ExcerptsRemoved {
24979        ids: Vec<ExcerptId>,
24980        removed_buffer_ids: Vec<BufferId>,
24981    },
24982    BufferFoldToggled {
24983        ids: Vec<ExcerptId>,
24984        folded: bool,
24985    },
24986    ExcerptsEdited {
24987        ids: Vec<ExcerptId>,
24988    },
24989    ExcerptsExpanded {
24990        ids: Vec<ExcerptId>,
24991    },
24992    BufferEdited,
24993    Edited {
24994        transaction_id: clock::Lamport,
24995    },
24996    Reparsed(BufferId),
24997    Focused,
24998    FocusedIn,
24999    Blurred,
25000    DirtyChanged,
25001    Saved,
25002    TitleChanged,
25003    SelectionsChanged {
25004        local: bool,
25005    },
25006    ScrollPositionChanged {
25007        local: bool,
25008        autoscroll: bool,
25009    },
25010    TransactionUndone {
25011        transaction_id: clock::Lamport,
25012    },
25013    TransactionBegun {
25014        transaction_id: clock::Lamport,
25015    },
25016    CursorShapeChanged,
25017    BreadcrumbsChanged,
25018    PushedToNavHistory {
25019        anchor: Anchor,
25020        is_deactivate: bool,
25021    },
25022}
25023
25024impl EventEmitter<EditorEvent> for Editor {}
25025
25026impl Focusable for Editor {
25027    fn focus_handle(&self, _cx: &App) -> FocusHandle {
25028        self.focus_handle.clone()
25029    }
25030}
25031
25032impl Render for Editor {
25033    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25034        EditorElement::new(&cx.entity(), self.create_style(cx))
25035    }
25036}
25037
25038impl EntityInputHandler for Editor {
25039    fn text_for_range(
25040        &mut self,
25041        range_utf16: Range<usize>,
25042        adjusted_range: &mut Option<Range<usize>>,
25043        _: &mut Window,
25044        cx: &mut Context<Self>,
25045    ) -> Option<String> {
25046        let snapshot = self.buffer.read(cx).read(cx);
25047        let start = snapshot.clip_offset_utf16(
25048            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
25049            Bias::Left,
25050        );
25051        let end = snapshot.clip_offset_utf16(
25052            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
25053            Bias::Right,
25054        );
25055        if (start.0.0..end.0.0) != range_utf16 {
25056            adjusted_range.replace(start.0.0..end.0.0);
25057        }
25058        Some(snapshot.text_for_range(start..end).collect())
25059    }
25060
25061    fn selected_text_range(
25062        &mut self,
25063        ignore_disabled_input: bool,
25064        _: &mut Window,
25065        cx: &mut Context<Self>,
25066    ) -> Option<UTF16Selection> {
25067        // Prevent the IME menu from appearing when holding down an alphabetic key
25068        // while input is disabled.
25069        if !ignore_disabled_input && !self.input_enabled {
25070            return None;
25071        }
25072
25073        let selection = self
25074            .selections
25075            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25076        let range = selection.range();
25077
25078        Some(UTF16Selection {
25079            range: range.start.0.0..range.end.0.0,
25080            reversed: selection.reversed,
25081        })
25082    }
25083
25084    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
25085        let snapshot = self.buffer.read(cx).read(cx);
25086        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
25087        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
25088    }
25089
25090    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25091        self.clear_highlights::<InputComposition>(cx);
25092        self.ime_transaction.take();
25093    }
25094
25095    fn replace_text_in_range(
25096        &mut self,
25097        range_utf16: Option<Range<usize>>,
25098        text: &str,
25099        window: &mut Window,
25100        cx: &mut Context<Self>,
25101    ) {
25102        if !self.input_enabled {
25103            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25104            return;
25105        }
25106
25107        self.transact(window, cx, |this, window, cx| {
25108            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
25109                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25110                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25111                Some(this.selection_replacement_ranges(range_utf16, cx))
25112            } else {
25113                this.marked_text_ranges(cx)
25114            };
25115
25116            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
25117                let newest_selection_id = this.selections.newest_anchor().id;
25118                this.selections
25119                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25120                    .iter()
25121                    .zip(ranges_to_replace.iter())
25122                    .find_map(|(selection, range)| {
25123                        if selection.id == newest_selection_id {
25124                            Some(
25125                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25126                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25127                            )
25128                        } else {
25129                            None
25130                        }
25131                    })
25132            });
25133
25134            cx.emit(EditorEvent::InputHandled {
25135                utf16_range_to_replace: range_to_replace,
25136                text: text.into(),
25137            });
25138
25139            if let Some(new_selected_ranges) = new_selected_ranges {
25140                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25141                    selections.select_ranges(new_selected_ranges)
25142                });
25143                this.backspace(&Default::default(), window, cx);
25144            }
25145
25146            this.handle_input(text, window, cx);
25147        });
25148
25149        if let Some(transaction) = self.ime_transaction {
25150            self.buffer.update(cx, |buffer, cx| {
25151                buffer.group_until_transaction(transaction, cx);
25152            });
25153        }
25154
25155        self.unmark_text(window, cx);
25156    }
25157
25158    fn replace_and_mark_text_in_range(
25159        &mut self,
25160        range_utf16: Option<Range<usize>>,
25161        text: &str,
25162        new_selected_range_utf16: Option<Range<usize>>,
25163        window: &mut Window,
25164        cx: &mut Context<Self>,
25165    ) {
25166        if !self.input_enabled {
25167            return;
25168        }
25169
25170        let transaction = self.transact(window, cx, |this, window, cx| {
25171            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
25172                let snapshot = this.buffer.read(cx).read(cx);
25173                if let Some(relative_range_utf16) = range_utf16.as_ref() {
25174                    for marked_range in &mut marked_ranges {
25175                        marked_range.end = marked_range.start + relative_range_utf16.end;
25176                        marked_range.start += relative_range_utf16.start;
25177                        marked_range.start =
25178                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
25179                        marked_range.end =
25180                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
25181                    }
25182                }
25183                Some(marked_ranges)
25184            } else if let Some(range_utf16) = range_utf16 {
25185                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25186                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25187                Some(this.selection_replacement_ranges(range_utf16, cx))
25188            } else {
25189                None
25190            };
25191
25192            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
25193                let newest_selection_id = this.selections.newest_anchor().id;
25194                this.selections
25195                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25196                    .iter()
25197                    .zip(ranges_to_replace.iter())
25198                    .find_map(|(selection, range)| {
25199                        if selection.id == newest_selection_id {
25200                            Some(
25201                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25202                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25203                            )
25204                        } else {
25205                            None
25206                        }
25207                    })
25208            });
25209
25210            cx.emit(EditorEvent::InputHandled {
25211                utf16_range_to_replace: range_to_replace,
25212                text: text.into(),
25213            });
25214
25215            if let Some(ranges) = ranges_to_replace {
25216                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25217                    s.select_ranges(ranges)
25218                });
25219            }
25220
25221            let marked_ranges = {
25222                let snapshot = this.buffer.read(cx).read(cx);
25223                this.selections
25224                    .disjoint_anchors_arc()
25225                    .iter()
25226                    .map(|selection| {
25227                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
25228                    })
25229                    .collect::<Vec<_>>()
25230            };
25231
25232            if text.is_empty() {
25233                this.unmark_text(window, cx);
25234            } else {
25235                this.highlight_text::<InputComposition>(
25236                    marked_ranges.clone(),
25237                    HighlightStyle {
25238                        underline: Some(UnderlineStyle {
25239                            thickness: px(1.),
25240                            color: None,
25241                            wavy: false,
25242                        }),
25243                        ..Default::default()
25244                    },
25245                    cx,
25246                );
25247            }
25248
25249            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
25250            let use_autoclose = this.use_autoclose;
25251            let use_auto_surround = this.use_auto_surround;
25252            this.set_use_autoclose(false);
25253            this.set_use_auto_surround(false);
25254            this.handle_input(text, window, cx);
25255            this.set_use_autoclose(use_autoclose);
25256            this.set_use_auto_surround(use_auto_surround);
25257
25258            if let Some(new_selected_range) = new_selected_range_utf16 {
25259                let snapshot = this.buffer.read(cx).read(cx);
25260                let new_selected_ranges = marked_ranges
25261                    .into_iter()
25262                    .map(|marked_range| {
25263                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
25264                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
25265                            insertion_start.0 + new_selected_range.start,
25266                        ));
25267                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
25268                            insertion_start.0 + new_selected_range.end,
25269                        ));
25270                        snapshot.clip_offset_utf16(new_start, Bias::Left)
25271                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
25272                    })
25273                    .collect::<Vec<_>>();
25274
25275                drop(snapshot);
25276                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25277                    selections.select_ranges(new_selected_ranges)
25278                });
25279            }
25280        });
25281
25282        self.ime_transaction = self.ime_transaction.or(transaction);
25283        if let Some(transaction) = self.ime_transaction {
25284            self.buffer.update(cx, |buffer, cx| {
25285                buffer.group_until_transaction(transaction, cx);
25286            });
25287        }
25288
25289        if self.text_highlights::<InputComposition>(cx).is_none() {
25290            self.ime_transaction.take();
25291        }
25292    }
25293
25294    fn bounds_for_range(
25295        &mut self,
25296        range_utf16: Range<usize>,
25297        element_bounds: gpui::Bounds<Pixels>,
25298        window: &mut Window,
25299        cx: &mut Context<Self>,
25300    ) -> Option<gpui::Bounds<Pixels>> {
25301        let text_layout_details = self.text_layout_details(window);
25302        let CharacterDimensions {
25303            em_width,
25304            em_advance,
25305            line_height,
25306        } = self.character_dimensions(window);
25307
25308        let snapshot = self.snapshot(window, cx);
25309        let scroll_position = snapshot.scroll_position();
25310        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
25311
25312        let start =
25313            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
25314        let x = Pixels::from(
25315            ScrollOffset::from(
25316                snapshot.x_for_display_point(start, &text_layout_details)
25317                    + self.gutter_dimensions.full_width(),
25318            ) - scroll_left,
25319        );
25320        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
25321
25322        Some(Bounds {
25323            origin: element_bounds.origin + point(x, y),
25324            size: size(em_width, line_height),
25325        })
25326    }
25327
25328    fn character_index_for_point(
25329        &mut self,
25330        point: gpui::Point<Pixels>,
25331        _window: &mut Window,
25332        _cx: &mut Context<Self>,
25333    ) -> Option<usize> {
25334        let position_map = self.last_position_map.as_ref()?;
25335        if !position_map.text_hitbox.contains(&point) {
25336            return None;
25337        }
25338        let display_point = position_map.point_for_position(point).previous_valid;
25339        let anchor = position_map
25340            .snapshot
25341            .display_point_to_anchor(display_point, Bias::Left);
25342        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
25343        Some(utf16_offset.0.0)
25344    }
25345
25346    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
25347        self.input_enabled
25348    }
25349}
25350
25351trait SelectionExt {
25352    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
25353    fn spanned_rows(
25354        &self,
25355        include_end_if_at_line_start: bool,
25356        map: &DisplaySnapshot,
25357    ) -> Range<MultiBufferRow>;
25358}
25359
25360impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
25361    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
25362        let start = self
25363            .start
25364            .to_point(map.buffer_snapshot())
25365            .to_display_point(map);
25366        let end = self
25367            .end
25368            .to_point(map.buffer_snapshot())
25369            .to_display_point(map);
25370        if self.reversed {
25371            end..start
25372        } else {
25373            start..end
25374        }
25375    }
25376
25377    fn spanned_rows(
25378        &self,
25379        include_end_if_at_line_start: bool,
25380        map: &DisplaySnapshot,
25381    ) -> Range<MultiBufferRow> {
25382        let start = self.start.to_point(map.buffer_snapshot());
25383        let mut end = self.end.to_point(map.buffer_snapshot());
25384        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
25385            end.row -= 1;
25386        }
25387
25388        let buffer_start = map.prev_line_boundary(start).0;
25389        let buffer_end = map.next_line_boundary(end).0;
25390        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
25391    }
25392}
25393
25394impl<T: InvalidationRegion> InvalidationStack<T> {
25395    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
25396    where
25397        S: Clone + ToOffset,
25398    {
25399        while let Some(region) = self.last() {
25400            let all_selections_inside_invalidation_ranges =
25401                if selections.len() == region.ranges().len() {
25402                    selections
25403                        .iter()
25404                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
25405                        .all(|(selection, invalidation_range)| {
25406                            let head = selection.head().to_offset(buffer);
25407                            invalidation_range.start <= head && invalidation_range.end >= head
25408                        })
25409                } else {
25410                    false
25411                };
25412
25413            if all_selections_inside_invalidation_ranges {
25414                break;
25415            } else {
25416                self.pop();
25417            }
25418        }
25419    }
25420}
25421
25422impl<T> Default for InvalidationStack<T> {
25423    fn default() -> Self {
25424        Self(Default::default())
25425    }
25426}
25427
25428impl<T> Deref for InvalidationStack<T> {
25429    type Target = Vec<T>;
25430
25431    fn deref(&self) -> &Self::Target {
25432        &self.0
25433    }
25434}
25435
25436impl<T> DerefMut for InvalidationStack<T> {
25437    fn deref_mut(&mut self) -> &mut Self::Target {
25438        &mut self.0
25439    }
25440}
25441
25442impl InvalidationRegion for SnippetState {
25443    fn ranges(&self) -> &[Range<Anchor>] {
25444        &self.ranges[self.active_index]
25445    }
25446}
25447
25448fn edit_prediction_edit_text(
25449    current_snapshot: &BufferSnapshot,
25450    edits: &[(Range<Anchor>, impl AsRef<str>)],
25451    edit_preview: &EditPreview,
25452    include_deletions: bool,
25453    cx: &App,
25454) -> HighlightedText {
25455    let edits = edits
25456        .iter()
25457        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
25458        .collect::<Vec<_>>();
25459
25460    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
25461}
25462
25463fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
25464    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
25465    // Just show the raw edit text with basic styling
25466    let mut text = String::new();
25467    let mut highlights = Vec::new();
25468
25469    let insertion_highlight_style = HighlightStyle {
25470        color: Some(cx.theme().colors().text),
25471        ..Default::default()
25472    };
25473
25474    for (_, edit_text) in edits {
25475        let start_offset = text.len();
25476        text.push_str(edit_text);
25477        let end_offset = text.len();
25478
25479        if start_offset < end_offset {
25480            highlights.push((start_offset..end_offset, insertion_highlight_style));
25481        }
25482    }
25483
25484    HighlightedText {
25485        text: text.into(),
25486        highlights,
25487    }
25488}
25489
25490pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
25491    match severity {
25492        lsp::DiagnosticSeverity::ERROR => colors.error,
25493        lsp::DiagnosticSeverity::WARNING => colors.warning,
25494        lsp::DiagnosticSeverity::INFORMATION => colors.info,
25495        lsp::DiagnosticSeverity::HINT => colors.info,
25496        _ => colors.ignored,
25497    }
25498}
25499
25500pub fn styled_runs_for_code_label<'a>(
25501    label: &'a CodeLabel,
25502    syntax_theme: &'a theme::SyntaxTheme,
25503    local_player: &'a theme::PlayerColor,
25504) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
25505    let fade_out = HighlightStyle {
25506        fade_out: Some(0.35),
25507        ..Default::default()
25508    };
25509
25510    let mut prev_end = label.filter_range.end;
25511    label
25512        .runs
25513        .iter()
25514        .enumerate()
25515        .flat_map(move |(ix, (range, highlight_id))| {
25516            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
25517                HighlightStyle {
25518                    color: Some(local_player.cursor),
25519                    ..Default::default()
25520                }
25521            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
25522                HighlightStyle {
25523                    background_color: Some(local_player.selection),
25524                    ..Default::default()
25525                }
25526            } else if let Some(style) = highlight_id.style(syntax_theme) {
25527                style
25528            } else {
25529                return Default::default();
25530            };
25531            let muted_style = style.highlight(fade_out);
25532
25533            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
25534            if range.start >= label.filter_range.end {
25535                if range.start > prev_end {
25536                    runs.push((prev_end..range.start, fade_out));
25537                }
25538                runs.push((range.clone(), muted_style));
25539            } else if range.end <= label.filter_range.end {
25540                runs.push((range.clone(), style));
25541            } else {
25542                runs.push((range.start..label.filter_range.end, style));
25543                runs.push((label.filter_range.end..range.end, muted_style));
25544            }
25545            prev_end = cmp::max(prev_end, range.end);
25546
25547            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
25548                runs.push((prev_end..label.text.len(), fade_out));
25549            }
25550
25551            runs
25552        })
25553}
25554
25555pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
25556    let mut prev_index = 0;
25557    let mut prev_codepoint: Option<char> = None;
25558    text.char_indices()
25559        .chain([(text.len(), '\0')])
25560        .filter_map(move |(index, codepoint)| {
25561            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25562            let is_boundary = index == text.len()
25563                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
25564                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
25565            if is_boundary {
25566                let chunk = &text[prev_index..index];
25567                prev_index = index;
25568                Some(chunk)
25569            } else {
25570                None
25571            }
25572        })
25573}
25574
25575/// Given a string of text immediately before the cursor, iterates over possible
25576/// strings a snippet could match to. More precisely: returns an iterator over
25577/// suffixes of `text` created by splitting at word boundaries (before & after
25578/// every non-word character).
25579///
25580/// Shorter suffixes are returned first.
25581pub(crate) fn snippet_candidate_suffixes(
25582    text: &str,
25583    is_word_char: impl Fn(char) -> bool,
25584) -> impl std::iter::Iterator<Item = &str> {
25585    let mut prev_index = text.len();
25586    let mut prev_codepoint = None;
25587    text.char_indices()
25588        .rev()
25589        .chain([(0, '\0')])
25590        .filter_map(move |(index, codepoint)| {
25591            let prev_index = std::mem::replace(&mut prev_index, index);
25592            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25593            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
25594                None
25595            } else {
25596                let chunk = &text[prev_index..]; // go to end of string
25597                Some(chunk)
25598            }
25599        })
25600}
25601
25602pub trait RangeToAnchorExt: Sized {
25603    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25604
25605    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25606        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25607        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25608    }
25609}
25610
25611impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25612    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25613        let start_offset = self.start.to_offset(snapshot);
25614        let end_offset = self.end.to_offset(snapshot);
25615        if start_offset == end_offset {
25616            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25617        } else {
25618            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25619        }
25620    }
25621}
25622
25623pub trait RowExt {
25624    fn as_f64(&self) -> f64;
25625
25626    fn next_row(&self) -> Self;
25627
25628    fn previous_row(&self) -> Self;
25629
25630    fn minus(&self, other: Self) -> u32;
25631}
25632
25633impl RowExt for DisplayRow {
25634    fn as_f64(&self) -> f64 {
25635        self.0 as _
25636    }
25637
25638    fn next_row(&self) -> Self {
25639        Self(self.0 + 1)
25640    }
25641
25642    fn previous_row(&self) -> Self {
25643        Self(self.0.saturating_sub(1))
25644    }
25645
25646    fn minus(&self, other: Self) -> u32 {
25647        self.0 - other.0
25648    }
25649}
25650
25651impl RowExt for MultiBufferRow {
25652    fn as_f64(&self) -> f64 {
25653        self.0 as _
25654    }
25655
25656    fn next_row(&self) -> Self {
25657        Self(self.0 + 1)
25658    }
25659
25660    fn previous_row(&self) -> Self {
25661        Self(self.0.saturating_sub(1))
25662    }
25663
25664    fn minus(&self, other: Self) -> u32 {
25665        self.0 - other.0
25666    }
25667}
25668
25669trait RowRangeExt {
25670    type Row;
25671
25672    fn len(&self) -> usize;
25673
25674    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25675}
25676
25677impl RowRangeExt for Range<MultiBufferRow> {
25678    type Row = MultiBufferRow;
25679
25680    fn len(&self) -> usize {
25681        (self.end.0 - self.start.0) as usize
25682    }
25683
25684    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25685        (self.start.0..self.end.0).map(MultiBufferRow)
25686    }
25687}
25688
25689impl RowRangeExt for Range<DisplayRow> {
25690    type Row = DisplayRow;
25691
25692    fn len(&self) -> usize {
25693        (self.end.0 - self.start.0) as usize
25694    }
25695
25696    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25697        (self.start.0..self.end.0).map(DisplayRow)
25698    }
25699}
25700
25701/// If select range has more than one line, we
25702/// just point the cursor to range.start.
25703fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25704    if range.start.row == range.end.row {
25705        range
25706    } else {
25707        range.start..range.start
25708    }
25709}
25710pub struct KillRing(ClipboardItem);
25711impl Global for KillRing {}
25712
25713const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25714
25715enum BreakpointPromptEditAction {
25716    Log,
25717    Condition,
25718    HitCondition,
25719}
25720
25721struct BreakpointPromptEditor {
25722    pub(crate) prompt: Entity<Editor>,
25723    editor: WeakEntity<Editor>,
25724    breakpoint_anchor: Anchor,
25725    breakpoint: Breakpoint,
25726    edit_action: BreakpointPromptEditAction,
25727    block_ids: HashSet<CustomBlockId>,
25728    editor_margins: Arc<Mutex<EditorMargins>>,
25729    _subscriptions: Vec<Subscription>,
25730}
25731
25732impl BreakpointPromptEditor {
25733    const MAX_LINES: u8 = 4;
25734
25735    fn new(
25736        editor: WeakEntity<Editor>,
25737        breakpoint_anchor: Anchor,
25738        breakpoint: Breakpoint,
25739        edit_action: BreakpointPromptEditAction,
25740        window: &mut Window,
25741        cx: &mut Context<Self>,
25742    ) -> Self {
25743        let base_text = match edit_action {
25744            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25745            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25746            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25747        }
25748        .map(|msg| msg.to_string())
25749        .unwrap_or_default();
25750
25751        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25752        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25753
25754        let prompt = cx.new(|cx| {
25755            let mut prompt = Editor::new(
25756                EditorMode::AutoHeight {
25757                    min_lines: 1,
25758                    max_lines: Some(Self::MAX_LINES as usize),
25759                },
25760                buffer,
25761                None,
25762                window,
25763                cx,
25764            );
25765            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25766            prompt.set_show_cursor_when_unfocused(false, cx);
25767            prompt.set_placeholder_text(
25768                match edit_action {
25769                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25770                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25771                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25772                },
25773                window,
25774                cx,
25775            );
25776
25777            prompt
25778        });
25779
25780        Self {
25781            prompt,
25782            editor,
25783            breakpoint_anchor,
25784            breakpoint,
25785            edit_action,
25786            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25787            block_ids: Default::default(),
25788            _subscriptions: vec![],
25789        }
25790    }
25791
25792    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25793        self.block_ids.extend(block_ids)
25794    }
25795
25796    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25797        if let Some(editor) = self.editor.upgrade() {
25798            let message = self
25799                .prompt
25800                .read(cx)
25801                .buffer
25802                .read(cx)
25803                .as_singleton()
25804                .expect("A multi buffer in breakpoint prompt isn't possible")
25805                .read(cx)
25806                .as_rope()
25807                .to_string();
25808
25809            editor.update(cx, |editor, cx| {
25810                editor.edit_breakpoint_at_anchor(
25811                    self.breakpoint_anchor,
25812                    self.breakpoint.clone(),
25813                    match self.edit_action {
25814                        BreakpointPromptEditAction::Log => {
25815                            BreakpointEditAction::EditLogMessage(message.into())
25816                        }
25817                        BreakpointPromptEditAction::Condition => {
25818                            BreakpointEditAction::EditCondition(message.into())
25819                        }
25820                        BreakpointPromptEditAction::HitCondition => {
25821                            BreakpointEditAction::EditHitCondition(message.into())
25822                        }
25823                    },
25824                    cx,
25825                );
25826
25827                editor.remove_blocks(self.block_ids.clone(), None, cx);
25828                cx.focus_self(window);
25829            });
25830        }
25831    }
25832
25833    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25834        self.editor
25835            .update(cx, |editor, cx| {
25836                editor.remove_blocks(self.block_ids.clone(), None, cx);
25837                window.focus(&editor.focus_handle);
25838            })
25839            .log_err();
25840    }
25841
25842    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25843        let settings = ThemeSettings::get_global(cx);
25844        let text_style = TextStyle {
25845            color: if self.prompt.read(cx).read_only(cx) {
25846                cx.theme().colors().text_disabled
25847            } else {
25848                cx.theme().colors().text
25849            },
25850            font_family: settings.buffer_font.family.clone(),
25851            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25852            font_size: settings.buffer_font_size(cx).into(),
25853            font_weight: settings.buffer_font.weight,
25854            line_height: relative(settings.buffer_line_height.value()),
25855            ..Default::default()
25856        };
25857        EditorElement::new(
25858            &self.prompt,
25859            EditorStyle {
25860                background: cx.theme().colors().editor_background,
25861                local_player: cx.theme().players().local(),
25862                text: text_style,
25863                ..Default::default()
25864            },
25865        )
25866    }
25867}
25868
25869impl Render for BreakpointPromptEditor {
25870    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25871        let editor_margins = *self.editor_margins.lock();
25872        let gutter_dimensions = editor_margins.gutter;
25873        h_flex()
25874            .key_context("Editor")
25875            .bg(cx.theme().colors().editor_background)
25876            .border_y_1()
25877            .border_color(cx.theme().status().info_border)
25878            .size_full()
25879            .py(window.line_height() / 2.5)
25880            .on_action(cx.listener(Self::confirm))
25881            .on_action(cx.listener(Self::cancel))
25882            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25883            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25884    }
25885}
25886
25887impl Focusable for BreakpointPromptEditor {
25888    fn focus_handle(&self, cx: &App) -> FocusHandle {
25889        self.prompt.focus_handle(cx)
25890    }
25891}
25892
25893fn all_edits_insertions_or_deletions(
25894    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25895    snapshot: &MultiBufferSnapshot,
25896) -> bool {
25897    let mut all_insertions = true;
25898    let mut all_deletions = true;
25899
25900    for (range, new_text) in edits.iter() {
25901        let range_is_empty = range.to_offset(snapshot).is_empty();
25902        let text_is_empty = new_text.is_empty();
25903
25904        if range_is_empty != text_is_empty {
25905            if range_is_empty {
25906                all_deletions = false;
25907            } else {
25908                all_insertions = false;
25909            }
25910        } else {
25911            return false;
25912        }
25913
25914        if !all_insertions && !all_deletions {
25915            return false;
25916        }
25917    }
25918    all_insertions || all_deletions
25919}
25920
25921struct MissingEditPredictionKeybindingTooltip;
25922
25923impl Render for MissingEditPredictionKeybindingTooltip {
25924    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25925        ui::tooltip_container(cx, |container, cx| {
25926            container
25927                .flex_shrink_0()
25928                .max_w_80()
25929                .min_h(rems_from_px(124.))
25930                .justify_between()
25931                .child(
25932                    v_flex()
25933                        .flex_1()
25934                        .text_ui_sm(cx)
25935                        .child(Label::new("Conflict with Accept Keybinding"))
25936                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25937                )
25938                .child(
25939                    h_flex()
25940                        .pb_1()
25941                        .gap_1()
25942                        .items_end()
25943                        .w_full()
25944                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25945                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25946                        }))
25947                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25948                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25949                        })),
25950                )
25951        })
25952    }
25953}
25954
25955#[derive(Debug, Clone, Copy, PartialEq)]
25956pub struct LineHighlight {
25957    pub background: Background,
25958    pub border: Option<gpui::Hsla>,
25959    pub include_gutter: bool,
25960    pub type_id: Option<TypeId>,
25961}
25962
25963struct LineManipulationResult {
25964    pub new_text: String,
25965    pub line_count_before: usize,
25966    pub line_count_after: usize,
25967}
25968
25969fn render_diff_hunk_controls(
25970    row: u32,
25971    status: &DiffHunkStatus,
25972    hunk_range: Range<Anchor>,
25973    is_created_file: bool,
25974    line_height: Pixels,
25975    editor: &Entity<Editor>,
25976    _window: &mut Window,
25977    cx: &mut App,
25978) -> AnyElement {
25979    h_flex()
25980        .h(line_height)
25981        .mr_1()
25982        .gap_1()
25983        .px_0p5()
25984        .pb_1()
25985        .border_x_1()
25986        .border_b_1()
25987        .border_color(cx.theme().colors().border_variant)
25988        .rounded_b_lg()
25989        .bg(cx.theme().colors().editor_background)
25990        .gap_1()
25991        .block_mouse_except_scroll()
25992        .shadow_md()
25993        .child(if status.has_secondary_hunk() {
25994            Button::new(("stage", row as u64), "Stage")
25995                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25996                .tooltip({
25997                    let focus_handle = editor.focus_handle(cx);
25998                    move |_window, cx| {
25999                        Tooltip::for_action_in(
26000                            "Stage Hunk",
26001                            &::git::ToggleStaged,
26002                            &focus_handle,
26003                            cx,
26004                        )
26005                    }
26006                })
26007                .on_click({
26008                    let editor = editor.clone();
26009                    move |_event, _window, cx| {
26010                        editor.update(cx, |editor, cx| {
26011                            editor.stage_or_unstage_diff_hunks(
26012                                true,
26013                                vec![hunk_range.start..hunk_range.start],
26014                                cx,
26015                            );
26016                        });
26017                    }
26018                })
26019        } else {
26020            Button::new(("unstage", row as u64), "Unstage")
26021                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26022                .tooltip({
26023                    let focus_handle = editor.focus_handle(cx);
26024                    move |_window, cx| {
26025                        Tooltip::for_action_in(
26026                            "Unstage Hunk",
26027                            &::git::ToggleStaged,
26028                            &focus_handle,
26029                            cx,
26030                        )
26031                    }
26032                })
26033                .on_click({
26034                    let editor = editor.clone();
26035                    move |_event, _window, cx| {
26036                        editor.update(cx, |editor, cx| {
26037                            editor.stage_or_unstage_diff_hunks(
26038                                false,
26039                                vec![hunk_range.start..hunk_range.start],
26040                                cx,
26041                            );
26042                        });
26043                    }
26044                })
26045        })
26046        .child(
26047            Button::new(("restore", row as u64), "Restore")
26048                .tooltip({
26049                    let focus_handle = editor.focus_handle(cx);
26050                    move |_window, cx| {
26051                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
26052                    }
26053                })
26054                .on_click({
26055                    let editor = editor.clone();
26056                    move |_event, window, cx| {
26057                        editor.update(cx, |editor, cx| {
26058                            let snapshot = editor.snapshot(window, cx);
26059                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
26060                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
26061                        });
26062                    }
26063                })
26064                .disabled(is_created_file),
26065        )
26066        .when(
26067            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
26068            |el| {
26069                el.child(
26070                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
26071                        .shape(IconButtonShape::Square)
26072                        .icon_size(IconSize::Small)
26073                        // .disabled(!has_multiple_hunks)
26074                        .tooltip({
26075                            let focus_handle = editor.focus_handle(cx);
26076                            move |_window, cx| {
26077                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
26078                            }
26079                        })
26080                        .on_click({
26081                            let editor = editor.clone();
26082                            move |_event, window, cx| {
26083                                editor.update(cx, |editor, cx| {
26084                                    let snapshot = editor.snapshot(window, cx);
26085                                    let position =
26086                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
26087                                    editor.go_to_hunk_before_or_after_position(
26088                                        &snapshot,
26089                                        position,
26090                                        Direction::Next,
26091                                        window,
26092                                        cx,
26093                                    );
26094                                    editor.expand_selected_diff_hunks(cx);
26095                                });
26096                            }
26097                        }),
26098                )
26099                .child(
26100                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
26101                        .shape(IconButtonShape::Square)
26102                        .icon_size(IconSize::Small)
26103                        // .disabled(!has_multiple_hunks)
26104                        .tooltip({
26105                            let focus_handle = editor.focus_handle(cx);
26106                            move |_window, cx| {
26107                                Tooltip::for_action_in(
26108                                    "Previous Hunk",
26109                                    &GoToPreviousHunk,
26110                                    &focus_handle,
26111                                    cx,
26112                                )
26113                            }
26114                        })
26115                        .on_click({
26116                            let editor = editor.clone();
26117                            move |_event, window, cx| {
26118                                editor.update(cx, |editor, cx| {
26119                                    let snapshot = editor.snapshot(window, cx);
26120                                    let point =
26121                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
26122                                    editor.go_to_hunk_before_or_after_position(
26123                                        &snapshot,
26124                                        point,
26125                                        Direction::Prev,
26126                                        window,
26127                                        cx,
26128                                    );
26129                                    editor.expand_selected_diff_hunks(cx);
26130                                });
26131                            }
26132                        }),
26133                )
26134            },
26135        )
26136        .into_any_element()
26137}
26138
26139pub fn multibuffer_context_lines(cx: &App) -> u32 {
26140    EditorSettings::try_get(cx)
26141        .map(|settings| settings.excerpt_context_lines)
26142        .unwrap_or(2)
26143        .min(32)
26144}