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::{
   96    EditPredictionDelegate, EditPredictionDelegateHandle, EditPredictionGranularity,
   97};
   98use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   99use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
  100use futures::{
  101    FutureExt, StreamExt as _,
  102    future::{self, Shared, join},
  103    stream::FuturesUnordered,
  104};
  105use fuzzy::{StringMatch, StringMatchCandidate};
  106use git::blame::{GitBlame, GlobalBlameRenderer};
  107use gpui::{
  108    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  109    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  110    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  111    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  112    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, PressureStage,
  113    Render, ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, TextRun,
  114    TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle,
  115    WeakEntity, WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative,
  116    size,
  117};
  118use hover_links::{HoverLink, HoveredLinkState, find_file};
  119use hover_popover::{HoverState, hide_hover};
  120use indent_guides::ActiveIndentGuidesState;
  121use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  122use itertools::{Either, Itertools};
  123use language::{
  124    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  125    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  126    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  127    IndentSize, Language, LanguageName, LanguageRegistry, LanguageScope, OffsetRangeExt,
  128    OutlineItem, Point, Runnable, Selection, SelectionGoal, TextObject, TransactionId,
  129    TreeSitterOptions, WordsQuery,
  130    language_settings::{
  131        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  132        all_language_settings, language_settings,
  133    },
  134    point_from_lsp, point_to_lsp, text_diff_with_options,
  135};
  136use linked_editing_ranges::refresh_linked_ranges;
  137use lsp::{
  138    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  139    LanguageServerId,
  140};
  141use lsp_colors::LspColorData;
  142use markdown::Markdown;
  143use mouse_context_menu::MouseContextMenu;
  144use movement::TextLayoutDetails;
  145use multi_buffer::{
  146    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  147};
  148use parking_lot::Mutex;
  149use persistence::DB;
  150use project::{
  151    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  152    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  153    InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project,
  154    ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  155    debugger::{
  156        breakpoint_store::{
  157            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  158            BreakpointStore, BreakpointStoreEvent,
  159        },
  160        session::{Session, SessionEvent},
  161    },
  162    git_store::GitStoreEvent,
  163    lsp_store::{
  164        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  165        OpenLspBufferHandle,
  166    },
  167    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  168};
  169use rand::seq::SliceRandom;
  170use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  171use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  172use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  173use serde::{Deserialize, Serialize};
  174use settings::{
  175    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  176    update_settings_file,
  177};
  178use smallvec::{SmallVec, smallvec};
  179use snippet::Snippet;
  180use std::{
  181    any::{Any, TypeId},
  182    borrow::Cow,
  183    cell::{OnceCell, RefCell},
  184    cmp::{self, Ordering, Reverse},
  185    collections::hash_map,
  186    iter::{self, Peekable},
  187    mem,
  188    num::NonZeroU32,
  189    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  190    path::{Path, PathBuf},
  191    rc::Rc,
  192    sync::Arc,
  193    time::{Duration, Instant},
  194};
  195use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  196use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  197use theme::{
  198    AccentColors, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  199    observe_buffer_font_size_adjustment,
  200};
  201use ui::{
  202    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  203    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  204};
  205use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  206use workspace::{
  207    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  208    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  209    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  210    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  211    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  212    searchable::SearchEvent,
  213};
  214
  215use crate::{
  216    code_context_menus::CompletionsMenuSource,
  217    editor_settings::MultiCursorModifier,
  218    hover_links::{find_url, find_url_from_range},
  219    inlays::{
  220        InlineValueCache,
  221        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  222    },
  223    scroll::{ScrollOffset, ScrollPixelOffset},
  224    selections_collection::resolve_selections_wrapping_blocks,
  225    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  226};
  227
  228pub const FILE_HEADER_HEIGHT: u32 = 2;
  229pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  230const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  231const MAX_LINE_LEN: usize = 1024;
  232const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  233const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  234pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  235#[doc(hidden)]
  236pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  237pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  238
  239pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  240pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  241pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  242pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  243
  244pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  245pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  246pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  247
  248pub type RenderDiffHunkControlsFn = Arc<
  249    dyn Fn(
  250        u32,
  251        &DiffHunkStatus,
  252        Range<Anchor>,
  253        bool,
  254        Pixels,
  255        &Entity<Editor>,
  256        &mut Window,
  257        &mut App,
  258    ) -> AnyElement,
  259>;
  260
  261enum ReportEditorEvent {
  262    Saved { auto_saved: bool },
  263    EditorOpened,
  264    Closed,
  265}
  266
  267impl ReportEditorEvent {
  268    pub fn event_type(&self) -> &'static str {
  269        match self {
  270            Self::Saved { .. } => "Editor Saved",
  271            Self::EditorOpened => "Editor Opened",
  272            Self::Closed => "Editor Closed",
  273        }
  274    }
  275}
  276
  277pub enum ActiveDebugLine {}
  278pub enum DebugStackFrameLine {}
  279enum DocumentHighlightRead {}
  280enum DocumentHighlightWrite {}
  281enum InputComposition {}
  282pub enum PendingInput {}
  283enum SelectedTextHighlight {}
  284
  285pub enum ConflictsOuter {}
  286pub enum ConflictsOurs {}
  287pub enum ConflictsTheirs {}
  288pub enum ConflictsOursMarker {}
  289pub enum ConflictsTheirsMarker {}
  290
  291pub struct HunkAddedColor;
  292pub struct HunkRemovedColor;
  293
  294#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  295pub enum Navigated {
  296    Yes,
  297    No,
  298}
  299
  300impl Navigated {
  301    pub fn from_bool(yes: bool) -> Navigated {
  302        if yes { Navigated::Yes } else { Navigated::No }
  303    }
  304}
  305
  306#[derive(Debug, Clone, PartialEq, Eq)]
  307enum DisplayDiffHunk {
  308    Folded {
  309        display_row: DisplayRow,
  310    },
  311    Unfolded {
  312        is_created_file: bool,
  313        diff_base_byte_range: Range<usize>,
  314        display_row_range: Range<DisplayRow>,
  315        multi_buffer_range: Range<Anchor>,
  316        status: DiffHunkStatus,
  317        word_diffs: Vec<Range<MultiBufferOffset>>,
  318    },
  319}
  320
  321pub enum HideMouseCursorOrigin {
  322    TypingAction,
  323    MovementAction,
  324}
  325
  326pub fn init(cx: &mut App) {
  327    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  328
  329    workspace::register_project_item::<Editor>(cx);
  330    workspace::FollowableViewRegistry::register::<Editor>(cx);
  331    workspace::register_serializable_item::<Editor>(cx);
  332
  333    cx.observe_new(
  334        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  335            workspace.register_action(Editor::new_file);
  336            workspace.register_action(Editor::new_file_split);
  337            workspace.register_action(Editor::new_file_vertical);
  338            workspace.register_action(Editor::new_file_horizontal);
  339            workspace.register_action(Editor::cancel_language_server_work);
  340            workspace.register_action(Editor::toggle_focus);
  341        },
  342    )
  343    .detach();
  344
  345    cx.on_action(move |_: &workspace::NewFile, cx| {
  346        let app_state = workspace::AppState::global(cx);
  347        if let Some(app_state) = app_state.upgrade() {
  348            workspace::open_new(
  349                Default::default(),
  350                app_state,
  351                cx,
  352                |workspace, window, cx| {
  353                    Editor::new_file(workspace, &Default::default(), window, cx)
  354                },
  355            )
  356            .detach();
  357        }
  358    })
  359    .on_action(move |_: &workspace::NewWindow, cx| {
  360        let app_state = workspace::AppState::global(cx);
  361        if let Some(app_state) = app_state.upgrade() {
  362            workspace::open_new(
  363                Default::default(),
  364                app_state,
  365                cx,
  366                |workspace, window, cx| {
  367                    cx.activate(true);
  368                    Editor::new_file(workspace, &Default::default(), window, cx)
  369                },
  370            )
  371            .detach();
  372        }
  373    });
  374}
  375
  376pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  377    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  378}
  379
  380pub trait DiagnosticRenderer {
  381    fn render_group(
  382        &self,
  383        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  384        buffer_id: BufferId,
  385        snapshot: EditorSnapshot,
  386        editor: WeakEntity<Editor>,
  387        language_registry: Option<Arc<LanguageRegistry>>,
  388        cx: &mut App,
  389    ) -> Vec<BlockProperties<Anchor>>;
  390
  391    fn render_hover(
  392        &self,
  393        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  394        range: Range<Point>,
  395        buffer_id: BufferId,
  396        language_registry: Option<Arc<LanguageRegistry>>,
  397        cx: &mut App,
  398    ) -> Option<Entity<markdown::Markdown>>;
  399
  400    fn open_link(
  401        &self,
  402        editor: &mut Editor,
  403        link: SharedString,
  404        window: &mut Window,
  405        cx: &mut Context<Editor>,
  406    );
  407}
  408
  409pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  410
  411impl GlobalDiagnosticRenderer {
  412    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  413        cx.try_global::<Self>().map(|g| g.0.clone())
  414    }
  415}
  416
  417impl gpui::Global for GlobalDiagnosticRenderer {}
  418pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  419    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  420}
  421
  422pub struct SearchWithinRange;
  423
  424trait InvalidationRegion {
  425    fn ranges(&self) -> &[Range<Anchor>];
  426}
  427
  428#[derive(Clone, Debug, PartialEq)]
  429pub enum SelectPhase {
  430    Begin {
  431        position: DisplayPoint,
  432        add: bool,
  433        click_count: usize,
  434    },
  435    BeginColumnar {
  436        position: DisplayPoint,
  437        reset: bool,
  438        mode: ColumnarMode,
  439        goal_column: u32,
  440    },
  441    Extend {
  442        position: DisplayPoint,
  443        click_count: usize,
  444    },
  445    Update {
  446        position: DisplayPoint,
  447        goal_column: u32,
  448        scroll_delta: gpui::Point<f32>,
  449    },
  450    End,
  451}
  452
  453#[derive(Clone, Debug, PartialEq)]
  454pub enum ColumnarMode {
  455    FromMouse,
  456    FromSelection,
  457}
  458
  459#[derive(Clone, Debug)]
  460pub enum SelectMode {
  461    Character,
  462    Word(Range<Anchor>),
  463    Line(Range<Anchor>),
  464    All,
  465}
  466
  467#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  468pub enum SizingBehavior {
  469    /// The editor will layout itself using `size_full` and will include the vertical
  470    /// scroll margin as requested by user settings.
  471    #[default]
  472    Default,
  473    /// The editor will layout itself using `size_full`, but will not have any
  474    /// vertical overscroll.
  475    ExcludeOverscrollMargin,
  476    /// The editor will request a vertical size according to its content and will be
  477    /// layouted without a vertical scroll margin.
  478    SizeByContent,
  479}
  480
  481#[derive(Clone, PartialEq, Eq, Debug)]
  482pub enum EditorMode {
  483    SingleLine,
  484    AutoHeight {
  485        min_lines: usize,
  486        max_lines: Option<usize>,
  487    },
  488    Full {
  489        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  490        scale_ui_elements_with_buffer_font_size: bool,
  491        /// When set to `true`, the editor will render a background for the active line.
  492        show_active_line_background: bool,
  493        /// Determines the sizing behavior for this editor
  494        sizing_behavior: SizingBehavior,
  495    },
  496    Minimap {
  497        parent: WeakEntity<Editor>,
  498    },
  499}
  500
  501impl EditorMode {
  502    pub fn full() -> Self {
  503        Self::Full {
  504            scale_ui_elements_with_buffer_font_size: true,
  505            show_active_line_background: true,
  506            sizing_behavior: SizingBehavior::Default,
  507        }
  508    }
  509
  510    #[inline]
  511    pub fn is_full(&self) -> bool {
  512        matches!(self, Self::Full { .. })
  513    }
  514
  515    #[inline]
  516    pub fn is_single_line(&self) -> bool {
  517        matches!(self, Self::SingleLine { .. })
  518    }
  519
  520    #[inline]
  521    fn is_minimap(&self) -> bool {
  522        matches!(self, Self::Minimap { .. })
  523    }
  524}
  525
  526#[derive(Copy, Clone, Debug)]
  527pub enum SoftWrap {
  528    /// Prefer not to wrap at all.
  529    ///
  530    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  531    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  532    GitDiff,
  533    /// Prefer a single line generally, unless an overly long line is encountered.
  534    None,
  535    /// Soft wrap lines that exceed the editor width.
  536    EditorWidth,
  537    /// Soft wrap lines at the preferred line length.
  538    Column(u32),
  539    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  540    Bounded(u32),
  541}
  542
  543#[derive(Clone)]
  544pub struct EditorStyle {
  545    pub background: Hsla,
  546    pub border: Hsla,
  547    pub local_player: PlayerColor,
  548    pub text: TextStyle,
  549    pub scrollbar_width: Pixels,
  550    pub syntax: Arc<SyntaxTheme>,
  551    pub status: StatusColors,
  552    pub inlay_hints_style: HighlightStyle,
  553    pub edit_prediction_styles: EditPredictionStyles,
  554    pub unnecessary_code_fade: f32,
  555    pub show_underlines: bool,
  556}
  557
  558impl Default for EditorStyle {
  559    fn default() -> Self {
  560        Self {
  561            background: Hsla::default(),
  562            border: Hsla::default(),
  563            local_player: PlayerColor::default(),
  564            text: TextStyle::default(),
  565            scrollbar_width: Pixels::default(),
  566            syntax: Default::default(),
  567            // HACK: Status colors don't have a real default.
  568            // We should look into removing the status colors from the editor
  569            // style and retrieve them directly from the theme.
  570            status: StatusColors::dark(),
  571            inlay_hints_style: HighlightStyle::default(),
  572            edit_prediction_styles: EditPredictionStyles {
  573                insertion: HighlightStyle::default(),
  574                whitespace: HighlightStyle::default(),
  575            },
  576            unnecessary_code_fade: Default::default(),
  577            show_underlines: true,
  578        }
  579    }
  580}
  581
  582pub fn make_inlay_hints_style(cx: &App) -> HighlightStyle {
  583    let show_background = language_settings::language_settings(None, None, cx)
  584        .inlay_hints
  585        .show_background;
  586
  587    let mut style = cx.theme().syntax().get("hint");
  588
  589    if style.color.is_none() {
  590        style.color = Some(cx.theme().status().hint);
  591    }
  592
  593    if !show_background {
  594        style.background_color = None;
  595        return style;
  596    }
  597
  598    if style.background_color.is_none() {
  599        style.background_color = Some(cx.theme().status().hint_background);
  600    }
  601
  602    style
  603}
  604
  605pub fn make_suggestion_styles(cx: &App) -> EditPredictionStyles {
  606    EditPredictionStyles {
  607        insertion: HighlightStyle {
  608            color: Some(cx.theme().status().predictive),
  609            ..HighlightStyle::default()
  610        },
  611        whitespace: HighlightStyle {
  612            background_color: Some(cx.theme().status().created_background),
  613            ..HighlightStyle::default()
  614        },
  615    }
  616}
  617
  618type CompletionId = usize;
  619
  620pub(crate) enum EditDisplayMode {
  621    TabAccept,
  622    DiffPopover,
  623    Inline,
  624}
  625
  626enum EditPrediction {
  627    Edit {
  628        edits: Vec<(Range<Anchor>, Arc<str>)>,
  629        edit_preview: Option<EditPreview>,
  630        display_mode: EditDisplayMode,
  631        snapshot: BufferSnapshot,
  632    },
  633    /// Move to a specific location in the active editor
  634    MoveWithin {
  635        target: Anchor,
  636        snapshot: BufferSnapshot,
  637    },
  638    /// Move to a specific location in a different editor (not the active one)
  639    MoveOutside {
  640        target: language::Anchor,
  641        snapshot: BufferSnapshot,
  642    },
  643}
  644
  645struct EditPredictionState {
  646    inlay_ids: Vec<InlayId>,
  647    completion: EditPrediction,
  648    completion_id: Option<SharedString>,
  649    invalidation_range: Option<Range<Anchor>>,
  650}
  651
  652enum EditPredictionSettings {
  653    Disabled,
  654    Enabled {
  655        show_in_menu: bool,
  656        preview_requires_modifier: bool,
  657    },
  658}
  659
  660enum EditPredictionHighlight {}
  661
  662#[derive(Debug, Clone)]
  663struct InlineDiagnostic {
  664    message: SharedString,
  665    group_id: usize,
  666    is_primary: bool,
  667    start: Point,
  668    severity: lsp::DiagnosticSeverity,
  669}
  670
  671pub enum MenuEditPredictionsPolicy {
  672    Never,
  673    ByProvider,
  674}
  675
  676pub enum EditPredictionPreview {
  677    /// Modifier is not pressed
  678    Inactive { released_too_fast: bool },
  679    /// Modifier pressed
  680    Active {
  681        since: Instant,
  682        previous_scroll_position: Option<ScrollAnchor>,
  683    },
  684}
  685
  686impl EditPredictionPreview {
  687    pub fn released_too_fast(&self) -> bool {
  688        match self {
  689            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  690            EditPredictionPreview::Active { .. } => false,
  691        }
  692    }
  693
  694    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  695        if let EditPredictionPreview::Active {
  696            previous_scroll_position,
  697            ..
  698        } = self
  699        {
  700            *previous_scroll_position = scroll_position;
  701        }
  702    }
  703}
  704
  705pub struct ContextMenuOptions {
  706    pub min_entries_visible: usize,
  707    pub max_entries_visible: usize,
  708    pub placement: Option<ContextMenuPlacement>,
  709}
  710
  711#[derive(Debug, Clone, PartialEq, Eq)]
  712pub enum ContextMenuPlacement {
  713    Above,
  714    Below,
  715}
  716
  717#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  718struct EditorActionId(usize);
  719
  720impl EditorActionId {
  721    pub fn post_inc(&mut self) -> Self {
  722        let answer = self.0;
  723
  724        *self = Self(answer + 1);
  725
  726        Self(answer)
  727    }
  728}
  729
  730// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  731// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  732
  733type BackgroundHighlight = (
  734    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  735    Arc<[Range<Anchor>]>,
  736);
  737type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  738
  739#[derive(Default)]
  740struct ScrollbarMarkerState {
  741    scrollbar_size: Size<Pixels>,
  742    dirty: bool,
  743    markers: Arc<[PaintQuad]>,
  744    pending_refresh: Option<Task<Result<()>>>,
  745}
  746
  747impl ScrollbarMarkerState {
  748    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  749        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  750    }
  751}
  752
  753#[derive(Clone, Copy, PartialEq, Eq)]
  754pub enum MinimapVisibility {
  755    Disabled,
  756    Enabled {
  757        /// The configuration currently present in the users settings.
  758        setting_configuration: bool,
  759        /// Whether to override the currently set visibility from the users setting.
  760        toggle_override: bool,
  761    },
  762}
  763
  764impl MinimapVisibility {
  765    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  766        if mode.is_full() {
  767            Self::Enabled {
  768                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  769                toggle_override: false,
  770            }
  771        } else {
  772            Self::Disabled
  773        }
  774    }
  775
  776    fn hidden(&self) -> Self {
  777        match *self {
  778            Self::Enabled {
  779                setting_configuration,
  780                ..
  781            } => Self::Enabled {
  782                setting_configuration,
  783                toggle_override: setting_configuration,
  784            },
  785            Self::Disabled => Self::Disabled,
  786        }
  787    }
  788
  789    fn disabled(&self) -> bool {
  790        matches!(*self, Self::Disabled)
  791    }
  792
  793    fn settings_visibility(&self) -> bool {
  794        match *self {
  795            Self::Enabled {
  796                setting_configuration,
  797                ..
  798            } => setting_configuration,
  799            _ => false,
  800        }
  801    }
  802
  803    fn visible(&self) -> bool {
  804        match *self {
  805            Self::Enabled {
  806                setting_configuration,
  807                toggle_override,
  808            } => setting_configuration ^ toggle_override,
  809            _ => false,
  810        }
  811    }
  812
  813    fn toggle_visibility(&self) -> Self {
  814        match *self {
  815            Self::Enabled {
  816                toggle_override,
  817                setting_configuration,
  818            } => Self::Enabled {
  819                setting_configuration,
  820                toggle_override: !toggle_override,
  821            },
  822            Self::Disabled => Self::Disabled,
  823        }
  824    }
  825}
  826
  827#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  828pub enum BufferSerialization {
  829    All,
  830    NonDirtyBuffers,
  831}
  832
  833impl BufferSerialization {
  834    fn new(restore_unsaved_buffers: bool) -> Self {
  835        if restore_unsaved_buffers {
  836            Self::All
  837        } else {
  838            Self::NonDirtyBuffers
  839        }
  840    }
  841}
  842
  843#[derive(Clone, Debug)]
  844struct RunnableTasks {
  845    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  846    offset: multi_buffer::Anchor,
  847    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  848    column: u32,
  849    // Values of all named captures, including those starting with '_'
  850    extra_variables: HashMap<String, String>,
  851    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  852    context_range: Range<BufferOffset>,
  853}
  854
  855impl RunnableTasks {
  856    fn resolve<'a>(
  857        &'a self,
  858        cx: &'a task::TaskContext,
  859    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  860        self.templates.iter().filter_map(|(kind, template)| {
  861            template
  862                .resolve_task(&kind.to_id_base(), cx)
  863                .map(|task| (kind.clone(), task))
  864        })
  865    }
  866}
  867
  868#[derive(Clone)]
  869pub struct ResolvedTasks {
  870    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  871    position: Anchor,
  872}
  873
  874/// Addons allow storing per-editor state in other crates (e.g. Vim)
  875pub trait Addon: 'static {
  876    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  877
  878    fn render_buffer_header_controls(
  879        &self,
  880        _: &ExcerptInfo,
  881        _: &Window,
  882        _: &App,
  883    ) -> Option<AnyElement> {
  884        None
  885    }
  886
  887    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  888        None
  889    }
  890
  891    fn to_any(&self) -> &dyn std::any::Any;
  892
  893    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  894        None
  895    }
  896}
  897
  898struct ChangeLocation {
  899    current: Option<Vec<Anchor>>,
  900    original: Vec<Anchor>,
  901}
  902impl ChangeLocation {
  903    fn locations(&self) -> &[Anchor] {
  904        self.current.as_ref().unwrap_or(&self.original)
  905    }
  906}
  907
  908/// A set of caret positions, registered when the editor was edited.
  909pub struct ChangeList {
  910    changes: Vec<ChangeLocation>,
  911    /// Currently "selected" change.
  912    position: Option<usize>,
  913}
  914
  915impl ChangeList {
  916    pub fn new() -> Self {
  917        Self {
  918            changes: Vec::new(),
  919            position: None,
  920        }
  921    }
  922
  923    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  924    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  925    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  926        if self.changes.is_empty() {
  927            return None;
  928        }
  929
  930        let prev = self.position.unwrap_or(self.changes.len());
  931        let next = if direction == Direction::Prev {
  932            prev.saturating_sub(count)
  933        } else {
  934            (prev + count).min(self.changes.len() - 1)
  935        };
  936        self.position = Some(next);
  937        self.changes.get(next).map(|change| change.locations())
  938    }
  939
  940    /// Adds a new change to the list, resetting the change list position.
  941    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  942        self.position.take();
  943        if let Some(last) = self.changes.last_mut()
  944            && group
  945        {
  946            last.current = Some(new_positions)
  947        } else {
  948            self.changes.push(ChangeLocation {
  949                original: new_positions,
  950                current: None,
  951            });
  952        }
  953    }
  954
  955    pub fn last(&self) -> Option<&[Anchor]> {
  956        self.changes.last().map(|change| change.locations())
  957    }
  958
  959    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  960        self.changes.last().map(|change| change.original.as_slice())
  961    }
  962
  963    pub fn invert_last_group(&mut self) {
  964        if let Some(last) = self.changes.last_mut()
  965            && let Some(current) = last.current.as_mut()
  966        {
  967            mem::swap(&mut last.original, current);
  968        }
  969    }
  970}
  971
  972#[derive(Clone)]
  973struct InlineBlamePopoverState {
  974    scroll_handle: ScrollHandle,
  975    commit_message: Option<ParsedCommitMessage>,
  976    markdown: Entity<Markdown>,
  977}
  978
  979struct InlineBlamePopover {
  980    position: gpui::Point<Pixels>,
  981    hide_task: Option<Task<()>>,
  982    popover_bounds: Option<Bounds<Pixels>>,
  983    popover_state: InlineBlamePopoverState,
  984    keyboard_grace: bool,
  985}
  986
  987enum SelectionDragState {
  988    /// State when no drag related activity is detected.
  989    None,
  990    /// State when the mouse is down on a selection that is about to be dragged.
  991    ReadyToDrag {
  992        selection: Selection<Anchor>,
  993        click_position: gpui::Point<Pixels>,
  994        mouse_down_time: Instant,
  995    },
  996    /// State when the mouse is dragging the selection in the editor.
  997    Dragging {
  998        selection: Selection<Anchor>,
  999        drop_cursor: Selection<Anchor>,
 1000        hide_drop_cursor: bool,
 1001    },
 1002}
 1003
 1004enum ColumnarSelectionState {
 1005    FromMouse {
 1006        selection_tail: Anchor,
 1007        display_point: Option<DisplayPoint>,
 1008    },
 1009    FromSelection {
 1010        selection_tail: Anchor,
 1011    },
 1012}
 1013
 1014/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1015/// a breakpoint on them.
 1016#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1017struct PhantomBreakpointIndicator {
 1018    display_row: DisplayRow,
 1019    /// There's a small debounce between hovering over the line and showing the indicator.
 1020    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1021    is_active: bool,
 1022    collides_with_existing_breakpoint: bool,
 1023}
 1024
 1025/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1026///
 1027/// See the [module level documentation](self) for more information.
 1028pub struct Editor {
 1029    focus_handle: FocusHandle,
 1030    last_focused_descendant: Option<WeakFocusHandle>,
 1031    /// The text buffer being edited
 1032    buffer: Entity<MultiBuffer>,
 1033    /// Map of how text in the buffer should be displayed.
 1034    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1035    pub display_map: Entity<DisplayMap>,
 1036    placeholder_display_map: Option<Entity<DisplayMap>>,
 1037    pub selections: SelectionsCollection,
 1038    pub scroll_manager: ScrollManager,
 1039    /// When inline assist editors are linked, they all render cursors because
 1040    /// typing enters text into each of them, even the ones that aren't focused.
 1041    pub(crate) show_cursor_when_unfocused: bool,
 1042    columnar_selection_state: Option<ColumnarSelectionState>,
 1043    add_selections_state: Option<AddSelectionsState>,
 1044    select_next_state: Option<SelectNextState>,
 1045    select_prev_state: Option<SelectNextState>,
 1046    selection_history: SelectionHistory,
 1047    defer_selection_effects: bool,
 1048    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1049    autoclose_regions: Vec<AutocloseRegion>,
 1050    snippet_stack: InvalidationStack<SnippetState>,
 1051    select_syntax_node_history: SelectSyntaxNodeHistory,
 1052    ime_transaction: Option<TransactionId>,
 1053    pub diagnostics_max_severity: DiagnosticSeverity,
 1054    active_diagnostics: ActiveDiagnostic,
 1055    show_inline_diagnostics: bool,
 1056    inline_diagnostics_update: Task<()>,
 1057    inline_diagnostics_enabled: bool,
 1058    diagnostics_enabled: bool,
 1059    word_completions_enabled: bool,
 1060    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1061    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1062    hard_wrap: Option<usize>,
 1063    project: Option<Entity<Project>>,
 1064    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1065    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1066    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1067    blink_manager: Entity<BlinkManager>,
 1068    show_cursor_names: bool,
 1069    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1070    pub show_local_selections: bool,
 1071    mode: EditorMode,
 1072    show_breadcrumbs: bool,
 1073    show_gutter: bool,
 1074    show_scrollbars: ScrollbarAxes,
 1075    minimap_visibility: MinimapVisibility,
 1076    offset_content: bool,
 1077    disable_expand_excerpt_buttons: bool,
 1078    show_line_numbers: Option<bool>,
 1079    use_relative_line_numbers: Option<bool>,
 1080    show_git_diff_gutter: Option<bool>,
 1081    show_code_actions: Option<bool>,
 1082    show_runnables: Option<bool>,
 1083    show_breakpoints: Option<bool>,
 1084    show_wrap_guides: Option<bool>,
 1085    show_indent_guides: Option<bool>,
 1086    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1087    highlight_order: usize,
 1088    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1089    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1090    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1091    scrollbar_marker_state: ScrollbarMarkerState,
 1092    active_indent_guides_state: ActiveIndentGuidesState,
 1093    nav_history: Option<ItemNavHistory>,
 1094    context_menu: RefCell<Option<CodeContextMenu>>,
 1095    context_menu_options: Option<ContextMenuOptions>,
 1096    mouse_context_menu: Option<MouseContextMenu>,
 1097    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1098    inline_blame_popover: Option<InlineBlamePopover>,
 1099    inline_blame_popover_show_task: Option<Task<()>>,
 1100    signature_help_state: SignatureHelpState,
 1101    auto_signature_help: Option<bool>,
 1102    find_all_references_task_sources: Vec<Anchor>,
 1103    next_completion_id: CompletionId,
 1104    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1105    code_actions_task: Option<Task<Result<()>>>,
 1106    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1107    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1108    document_highlights_task: Option<Task<()>>,
 1109    linked_editing_range_task: Option<Task<Option<()>>>,
 1110    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1111    pending_rename: Option<RenameState>,
 1112    searchable: bool,
 1113    cursor_shape: CursorShape,
 1114    /// Whether the cursor is offset one character to the left when something is
 1115    /// selected (needed for vim visual mode)
 1116    cursor_offset_on_selection: bool,
 1117    current_line_highlight: Option<CurrentLineHighlight>,
 1118    pub collapse_matches: bool,
 1119    autoindent_mode: Option<AutoindentMode>,
 1120    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1121    input_enabled: bool,
 1122    use_modal_editing: bool,
 1123    read_only: bool,
 1124    leader_id: Option<CollaboratorId>,
 1125    remote_id: Option<ViewId>,
 1126    pub hover_state: HoverState,
 1127    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1128    prev_pressure_stage: Option<PressureStage>,
 1129    gutter_hovered: bool,
 1130    hovered_link_state: Option<HoveredLinkState>,
 1131    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1132    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1133    active_edit_prediction: Option<EditPredictionState>,
 1134    /// Used to prevent flickering as the user types while the menu is open
 1135    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1136    edit_prediction_settings: EditPredictionSettings,
 1137    edit_predictions_hidden_for_vim_mode: bool,
 1138    show_edit_predictions_override: Option<bool>,
 1139    show_completions_on_input_override: Option<bool>,
 1140    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1141    edit_prediction_preview: EditPredictionPreview,
 1142    edit_prediction_indent_conflict: bool,
 1143    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1144    next_inlay_id: usize,
 1145    next_color_inlay_id: usize,
 1146    _subscriptions: Vec<Subscription>,
 1147    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1148    gutter_dimensions: GutterDimensions,
 1149    style: Option<EditorStyle>,
 1150    text_style_refinement: Option<TextStyleRefinement>,
 1151    next_editor_action_id: EditorActionId,
 1152    editor_actions: Rc<
 1153        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1154    >,
 1155    use_autoclose: bool,
 1156    use_auto_surround: bool,
 1157    auto_replace_emoji_shortcode: bool,
 1158    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1159    show_git_blame_gutter: bool,
 1160    show_git_blame_inline: bool,
 1161    show_git_blame_inline_delay_task: Option<Task<()>>,
 1162    git_blame_inline_enabled: bool,
 1163    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1164    buffer_serialization: Option<BufferSerialization>,
 1165    show_selection_menu: Option<bool>,
 1166    blame: Option<Entity<GitBlame>>,
 1167    blame_subscription: Option<Subscription>,
 1168    custom_context_menu: Option<
 1169        Box<
 1170            dyn 'static
 1171                + Fn(
 1172                    &mut Self,
 1173                    DisplayPoint,
 1174                    &mut Window,
 1175                    &mut Context<Self>,
 1176                ) -> Option<Entity<ui::ContextMenu>>,
 1177        >,
 1178    >,
 1179    last_bounds: Option<Bounds<Pixels>>,
 1180    last_position_map: Option<Rc<PositionMap>>,
 1181    expect_bounds_change: Option<Bounds<Pixels>>,
 1182    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1183    tasks_update_task: Option<Task<()>>,
 1184    breakpoint_store: Option<Entity<BreakpointStore>>,
 1185    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1186    hovered_diff_hunk_row: Option<DisplayRow>,
 1187    pull_diagnostics_task: Task<()>,
 1188    pull_diagnostics_background_task: Task<()>,
 1189    in_project_search: bool,
 1190    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1191    breadcrumb_header: Option<String>,
 1192    focused_block: Option<FocusedBlock>,
 1193    next_scroll_position: NextScrollCursorCenterTopBottom,
 1194    addons: HashMap<TypeId, Box<dyn Addon>>,
 1195    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1196    load_diff_task: Option<Shared<Task<()>>>,
 1197    /// Whether we are temporarily displaying a diff other than git's
 1198    temporary_diff_override: bool,
 1199    selection_mark_mode: bool,
 1200    toggle_fold_multiple_buffers: Task<()>,
 1201    _scroll_cursor_center_top_bottom_task: Task<()>,
 1202    serialize_selections: Task<()>,
 1203    serialize_folds: Task<()>,
 1204    mouse_cursor_hidden: bool,
 1205    minimap: Option<Entity<Self>>,
 1206    hide_mouse_mode: HideMouseMode,
 1207    pub change_list: ChangeList,
 1208    inline_value_cache: InlineValueCache,
 1209
 1210    selection_drag_state: SelectionDragState,
 1211    colors: Option<LspColorData>,
 1212    post_scroll_update: Task<()>,
 1213    refresh_colors_task: Task<()>,
 1214    inlay_hints: Option<LspInlayHintData>,
 1215    folding_newlines: Task<()>,
 1216    select_next_is_case_sensitive: Option<bool>,
 1217    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1218    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1219    accent_data: Option<AccentData>,
 1220    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1221    use_base_text_line_numbers: bool,
 1222}
 1223
 1224#[derive(Debug, PartialEq)]
 1225struct AccentData {
 1226    colors: AccentColors,
 1227    overrides: Vec<SharedString>,
 1228}
 1229
 1230fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1231    if debounce_ms > 0 {
 1232        Some(Duration::from_millis(debounce_ms))
 1233    } else {
 1234        None
 1235    }
 1236}
 1237
 1238#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1239enum NextScrollCursorCenterTopBottom {
 1240    #[default]
 1241    Center,
 1242    Top,
 1243    Bottom,
 1244}
 1245
 1246impl NextScrollCursorCenterTopBottom {
 1247    fn next(&self) -> Self {
 1248        match self {
 1249            Self::Center => Self::Top,
 1250            Self::Top => Self::Bottom,
 1251            Self::Bottom => Self::Center,
 1252        }
 1253    }
 1254}
 1255
 1256#[derive(Clone)]
 1257pub struct EditorSnapshot {
 1258    pub mode: EditorMode,
 1259    show_gutter: bool,
 1260    offset_content: bool,
 1261    show_line_numbers: Option<bool>,
 1262    show_git_diff_gutter: Option<bool>,
 1263    show_code_actions: Option<bool>,
 1264    show_runnables: Option<bool>,
 1265    show_breakpoints: Option<bool>,
 1266    git_blame_gutter_max_author_length: Option<usize>,
 1267    pub display_snapshot: DisplaySnapshot,
 1268    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1269    is_focused: bool,
 1270    scroll_anchor: ScrollAnchor,
 1271    ongoing_scroll: OngoingScroll,
 1272    current_line_highlight: CurrentLineHighlight,
 1273    gutter_hovered: bool,
 1274}
 1275
 1276#[derive(Default, Debug, Clone, Copy)]
 1277pub struct GutterDimensions {
 1278    pub left_padding: Pixels,
 1279    pub right_padding: Pixels,
 1280    pub width: Pixels,
 1281    pub margin: Pixels,
 1282    pub git_blame_entries_width: Option<Pixels>,
 1283}
 1284
 1285impl GutterDimensions {
 1286    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1287        Self {
 1288            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1289            ..Default::default()
 1290        }
 1291    }
 1292
 1293    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1294        -cx.text_system().descent(font_id, font_size)
 1295    }
 1296    /// The full width of the space taken up by the gutter.
 1297    pub fn full_width(&self) -> Pixels {
 1298        self.margin + self.width
 1299    }
 1300
 1301    /// The width of the space reserved for the fold indicators,
 1302    /// use alongside 'justify_end' and `gutter_width` to
 1303    /// right align content with the line numbers
 1304    pub fn fold_area_width(&self) -> Pixels {
 1305        self.margin + self.right_padding
 1306    }
 1307}
 1308
 1309struct CharacterDimensions {
 1310    em_width: Pixels,
 1311    em_advance: Pixels,
 1312    line_height: Pixels,
 1313}
 1314
 1315#[derive(Debug)]
 1316pub struct RemoteSelection {
 1317    pub replica_id: ReplicaId,
 1318    pub selection: Selection<Anchor>,
 1319    pub cursor_shape: CursorShape,
 1320    pub collaborator_id: CollaboratorId,
 1321    pub line_mode: bool,
 1322    pub user_name: Option<SharedString>,
 1323    pub color: PlayerColor,
 1324}
 1325
 1326#[derive(Clone, Debug)]
 1327struct SelectionHistoryEntry {
 1328    selections: Arc<[Selection<Anchor>]>,
 1329    select_next_state: Option<SelectNextState>,
 1330    select_prev_state: Option<SelectNextState>,
 1331    add_selections_state: Option<AddSelectionsState>,
 1332}
 1333
 1334#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1335enum SelectionHistoryMode {
 1336    #[default]
 1337    Normal,
 1338    Undoing,
 1339    Redoing,
 1340    Skipping,
 1341}
 1342
 1343#[derive(Clone, PartialEq, Eq, Hash)]
 1344struct HoveredCursor {
 1345    replica_id: ReplicaId,
 1346    selection_id: usize,
 1347}
 1348
 1349#[derive(Debug)]
 1350/// SelectionEffects controls the side-effects of updating the selection.
 1351///
 1352/// The default behaviour does "what you mostly want":
 1353/// - it pushes to the nav history if the cursor moved by >10 lines
 1354/// - it re-triggers completion requests
 1355/// - it scrolls to fit
 1356///
 1357/// You might want to modify these behaviours. For example when doing a "jump"
 1358/// like go to definition, we always want to add to nav history; but when scrolling
 1359/// in vim mode we never do.
 1360///
 1361/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1362/// move.
 1363#[derive(Clone)]
 1364pub struct SelectionEffects {
 1365    nav_history: Option<bool>,
 1366    completions: bool,
 1367    scroll: Option<Autoscroll>,
 1368}
 1369
 1370impl Default for SelectionEffects {
 1371    fn default() -> Self {
 1372        Self {
 1373            nav_history: None,
 1374            completions: true,
 1375            scroll: Some(Autoscroll::fit()),
 1376        }
 1377    }
 1378}
 1379impl SelectionEffects {
 1380    pub fn scroll(scroll: Autoscroll) -> Self {
 1381        Self {
 1382            scroll: Some(scroll),
 1383            ..Default::default()
 1384        }
 1385    }
 1386
 1387    pub fn no_scroll() -> Self {
 1388        Self {
 1389            scroll: None,
 1390            ..Default::default()
 1391        }
 1392    }
 1393
 1394    pub fn completions(self, completions: bool) -> Self {
 1395        Self {
 1396            completions,
 1397            ..self
 1398        }
 1399    }
 1400
 1401    pub fn nav_history(self, nav_history: bool) -> Self {
 1402        Self {
 1403            nav_history: Some(nav_history),
 1404            ..self
 1405        }
 1406    }
 1407}
 1408
 1409struct DeferredSelectionEffectsState {
 1410    changed: bool,
 1411    effects: SelectionEffects,
 1412    old_cursor_position: Anchor,
 1413    history_entry: SelectionHistoryEntry,
 1414}
 1415
 1416#[derive(Default)]
 1417struct SelectionHistory {
 1418    #[allow(clippy::type_complexity)]
 1419    selections_by_transaction:
 1420        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1421    mode: SelectionHistoryMode,
 1422    undo_stack: VecDeque<SelectionHistoryEntry>,
 1423    redo_stack: VecDeque<SelectionHistoryEntry>,
 1424}
 1425
 1426impl SelectionHistory {
 1427    #[track_caller]
 1428    fn insert_transaction(
 1429        &mut self,
 1430        transaction_id: TransactionId,
 1431        selections: Arc<[Selection<Anchor>]>,
 1432    ) {
 1433        if selections.is_empty() {
 1434            log::error!(
 1435                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1436                std::panic::Location::caller()
 1437            );
 1438            return;
 1439        }
 1440        self.selections_by_transaction
 1441            .insert(transaction_id, (selections, None));
 1442    }
 1443
 1444    #[allow(clippy::type_complexity)]
 1445    fn transaction(
 1446        &self,
 1447        transaction_id: TransactionId,
 1448    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1449        self.selections_by_transaction.get(&transaction_id)
 1450    }
 1451
 1452    #[allow(clippy::type_complexity)]
 1453    fn transaction_mut(
 1454        &mut self,
 1455        transaction_id: TransactionId,
 1456    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1457        self.selections_by_transaction.get_mut(&transaction_id)
 1458    }
 1459
 1460    fn push(&mut self, entry: SelectionHistoryEntry) {
 1461        if !entry.selections.is_empty() {
 1462            match self.mode {
 1463                SelectionHistoryMode::Normal => {
 1464                    self.push_undo(entry);
 1465                    self.redo_stack.clear();
 1466                }
 1467                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1468                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1469                SelectionHistoryMode::Skipping => {}
 1470            }
 1471        }
 1472    }
 1473
 1474    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1475        if self
 1476            .undo_stack
 1477            .back()
 1478            .is_none_or(|e| e.selections != entry.selections)
 1479        {
 1480            self.undo_stack.push_back(entry);
 1481            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1482                self.undo_stack.pop_front();
 1483            }
 1484        }
 1485    }
 1486
 1487    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1488        if self
 1489            .redo_stack
 1490            .back()
 1491            .is_none_or(|e| e.selections != entry.selections)
 1492        {
 1493            self.redo_stack.push_back(entry);
 1494            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1495                self.redo_stack.pop_front();
 1496            }
 1497        }
 1498    }
 1499}
 1500
 1501#[derive(Clone, Copy)]
 1502pub struct RowHighlightOptions {
 1503    pub autoscroll: bool,
 1504    pub include_gutter: bool,
 1505}
 1506
 1507impl Default for RowHighlightOptions {
 1508    fn default() -> Self {
 1509        Self {
 1510            autoscroll: Default::default(),
 1511            include_gutter: true,
 1512        }
 1513    }
 1514}
 1515
 1516struct RowHighlight {
 1517    index: usize,
 1518    range: Range<Anchor>,
 1519    color: Hsla,
 1520    options: RowHighlightOptions,
 1521    type_id: TypeId,
 1522}
 1523
 1524#[derive(Clone, Debug)]
 1525struct AddSelectionsState {
 1526    groups: Vec<AddSelectionsGroup>,
 1527}
 1528
 1529#[derive(Clone, Debug)]
 1530struct AddSelectionsGroup {
 1531    above: bool,
 1532    stack: Vec<usize>,
 1533}
 1534
 1535#[derive(Clone)]
 1536struct SelectNextState {
 1537    query: AhoCorasick,
 1538    wordwise: bool,
 1539    done: bool,
 1540}
 1541
 1542impl std::fmt::Debug for SelectNextState {
 1543    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1544        f.debug_struct(std::any::type_name::<Self>())
 1545            .field("wordwise", &self.wordwise)
 1546            .field("done", &self.done)
 1547            .finish()
 1548    }
 1549}
 1550
 1551#[derive(Debug)]
 1552struct AutocloseRegion {
 1553    selection_id: usize,
 1554    range: Range<Anchor>,
 1555    pair: BracketPair,
 1556}
 1557
 1558#[derive(Debug)]
 1559struct SnippetState {
 1560    ranges: Vec<Vec<Range<Anchor>>>,
 1561    active_index: usize,
 1562    choices: Vec<Option<Vec<String>>>,
 1563}
 1564
 1565#[doc(hidden)]
 1566pub struct RenameState {
 1567    pub range: Range<Anchor>,
 1568    pub old_name: Arc<str>,
 1569    pub editor: Entity<Editor>,
 1570    block_id: CustomBlockId,
 1571}
 1572
 1573struct InvalidationStack<T>(Vec<T>);
 1574
 1575struct RegisteredEditPredictionDelegate {
 1576    provider: Arc<dyn EditPredictionDelegateHandle>,
 1577    _subscription: Subscription,
 1578}
 1579
 1580#[derive(Debug, PartialEq, Eq)]
 1581pub struct ActiveDiagnosticGroup {
 1582    pub active_range: Range<Anchor>,
 1583    pub active_message: String,
 1584    pub group_id: usize,
 1585    pub blocks: HashSet<CustomBlockId>,
 1586}
 1587
 1588#[derive(Debug, PartialEq, Eq)]
 1589
 1590pub(crate) enum ActiveDiagnostic {
 1591    None,
 1592    All,
 1593    Group(ActiveDiagnosticGroup),
 1594}
 1595
 1596#[derive(Serialize, Deserialize, Clone, Debug)]
 1597pub struct ClipboardSelection {
 1598    /// The number of bytes in this selection.
 1599    pub len: usize,
 1600    /// Whether this was a full-line selection.
 1601    pub is_entire_line: bool,
 1602    /// The indentation of the first line when this content was originally copied.
 1603    pub first_line_indent: u32,
 1604    #[serde(default)]
 1605    pub file_path: Option<PathBuf>,
 1606    #[serde(default)]
 1607    pub line_range: Option<RangeInclusive<u32>>,
 1608}
 1609
 1610impl ClipboardSelection {
 1611    pub fn for_buffer(
 1612        len: usize,
 1613        is_entire_line: bool,
 1614        range: Range<Point>,
 1615        buffer: &MultiBufferSnapshot,
 1616        project: Option<&Entity<Project>>,
 1617        cx: &App,
 1618    ) -> Self {
 1619        let first_line_indent = buffer
 1620            .indent_size_for_line(MultiBufferRow(range.start.row))
 1621            .len;
 1622
 1623        let file_path = util::maybe!({
 1624            let project = project?.read(cx);
 1625            let file = buffer.file_at(range.start)?;
 1626            let project_path = ProjectPath {
 1627                worktree_id: file.worktree_id(cx),
 1628                path: file.path().clone(),
 1629            };
 1630            project.absolute_path(&project_path, cx)
 1631        });
 1632
 1633        let line_range = file_path.as_ref().map(|_| range.start.row..=range.end.row);
 1634
 1635        Self {
 1636            len,
 1637            is_entire_line,
 1638            first_line_indent,
 1639            file_path,
 1640            line_range,
 1641        }
 1642    }
 1643}
 1644
 1645// selections, scroll behavior, was newest selection reversed
 1646type SelectSyntaxNodeHistoryState = (
 1647    Box<[Selection<MultiBufferOffset>]>,
 1648    SelectSyntaxNodeScrollBehavior,
 1649    bool,
 1650);
 1651
 1652#[derive(Default)]
 1653struct SelectSyntaxNodeHistory {
 1654    stack: Vec<SelectSyntaxNodeHistoryState>,
 1655    // disable temporarily to allow changing selections without losing the stack
 1656    pub disable_clearing: bool,
 1657}
 1658
 1659impl SelectSyntaxNodeHistory {
 1660    pub fn try_clear(&mut self) {
 1661        if !self.disable_clearing {
 1662            self.stack.clear();
 1663        }
 1664    }
 1665
 1666    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1667        self.stack.push(selection);
 1668    }
 1669
 1670    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1671        self.stack.pop()
 1672    }
 1673}
 1674
 1675enum SelectSyntaxNodeScrollBehavior {
 1676    CursorTop,
 1677    FitSelection,
 1678    CursorBottom,
 1679}
 1680
 1681#[derive(Debug)]
 1682pub(crate) struct NavigationData {
 1683    cursor_anchor: Anchor,
 1684    cursor_position: Point,
 1685    scroll_anchor: ScrollAnchor,
 1686    scroll_top_row: u32,
 1687}
 1688
 1689#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1690pub enum GotoDefinitionKind {
 1691    Symbol,
 1692    Declaration,
 1693    Type,
 1694    Implementation,
 1695}
 1696
 1697pub enum FormatTarget {
 1698    Buffers(HashSet<Entity<Buffer>>),
 1699    Ranges(Vec<Range<MultiBufferPoint>>),
 1700}
 1701
 1702pub(crate) struct FocusedBlock {
 1703    id: BlockId,
 1704    focus_handle: WeakFocusHandle,
 1705}
 1706
 1707#[derive(Clone, Debug)]
 1708enum JumpData {
 1709    MultiBufferRow {
 1710        row: MultiBufferRow,
 1711        line_offset_from_top: u32,
 1712    },
 1713    MultiBufferPoint {
 1714        excerpt_id: ExcerptId,
 1715        position: Point,
 1716        anchor: text::Anchor,
 1717        line_offset_from_top: u32,
 1718    },
 1719}
 1720
 1721pub enum MultibufferSelectionMode {
 1722    First,
 1723    All,
 1724}
 1725
 1726#[derive(Clone, Copy, Debug, Default)]
 1727pub struct RewrapOptions {
 1728    pub override_language_settings: bool,
 1729    pub preserve_existing_whitespace: bool,
 1730}
 1731
 1732impl Editor {
 1733    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1734        let buffer = cx.new(|cx| Buffer::local("", cx));
 1735        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1736        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1737    }
 1738
 1739    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1740        let buffer = cx.new(|cx| Buffer::local("", cx));
 1741        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1742        Self::new(EditorMode::full(), buffer, None, window, cx)
 1743    }
 1744
 1745    pub fn auto_height(
 1746        min_lines: usize,
 1747        max_lines: usize,
 1748        window: &mut Window,
 1749        cx: &mut Context<Self>,
 1750    ) -> Self {
 1751        let buffer = cx.new(|cx| Buffer::local("", cx));
 1752        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1753        Self::new(
 1754            EditorMode::AutoHeight {
 1755                min_lines,
 1756                max_lines: Some(max_lines),
 1757            },
 1758            buffer,
 1759            None,
 1760            window,
 1761            cx,
 1762        )
 1763    }
 1764
 1765    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1766    /// The editor grows as tall as needed to fit its content.
 1767    pub fn auto_height_unbounded(
 1768        min_lines: usize,
 1769        window: &mut Window,
 1770        cx: &mut Context<Self>,
 1771    ) -> Self {
 1772        let buffer = cx.new(|cx| Buffer::local("", cx));
 1773        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1774        Self::new(
 1775            EditorMode::AutoHeight {
 1776                min_lines,
 1777                max_lines: None,
 1778            },
 1779            buffer,
 1780            None,
 1781            window,
 1782            cx,
 1783        )
 1784    }
 1785
 1786    pub fn for_buffer(
 1787        buffer: Entity<Buffer>,
 1788        project: Option<Entity<Project>>,
 1789        window: &mut Window,
 1790        cx: &mut Context<Self>,
 1791    ) -> Self {
 1792        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1793        Self::new(EditorMode::full(), buffer, project, window, cx)
 1794    }
 1795
 1796    pub fn for_multibuffer(
 1797        buffer: Entity<MultiBuffer>,
 1798        project: Option<Entity<Project>>,
 1799        window: &mut Window,
 1800        cx: &mut Context<Self>,
 1801    ) -> Self {
 1802        Self::new(EditorMode::full(), buffer, project, window, cx)
 1803    }
 1804
 1805    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1806        let mut clone = Self::new(
 1807            self.mode.clone(),
 1808            self.buffer.clone(),
 1809            self.project.clone(),
 1810            window,
 1811            cx,
 1812        );
 1813        self.display_map.update(cx, |display_map, cx| {
 1814            let snapshot = display_map.snapshot(cx);
 1815            clone.display_map.update(cx, |display_map, cx| {
 1816                display_map.set_state(&snapshot, cx);
 1817            });
 1818        });
 1819        clone.folds_did_change(cx);
 1820        clone.selections.clone_state(&self.selections);
 1821        clone.scroll_manager.clone_state(&self.scroll_manager);
 1822        clone.searchable = self.searchable;
 1823        clone.read_only = self.read_only;
 1824        clone
 1825    }
 1826
 1827    pub fn new(
 1828        mode: EditorMode,
 1829        buffer: Entity<MultiBuffer>,
 1830        project: Option<Entity<Project>>,
 1831        window: &mut Window,
 1832        cx: &mut Context<Self>,
 1833    ) -> Self {
 1834        Editor::new_internal(mode, buffer, project, None, window, cx)
 1835    }
 1836
 1837    pub fn sticky_headers(
 1838        &self,
 1839        style: &EditorStyle,
 1840        cx: &App,
 1841    ) -> Option<Vec<OutlineItem<Anchor>>> {
 1842        let multi_buffer = self.buffer().read(cx);
 1843        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1844        let multi_buffer_visible_start = self
 1845            .scroll_manager
 1846            .anchor()
 1847            .anchor
 1848            .to_point(&multi_buffer_snapshot);
 1849        let max_row = multi_buffer_snapshot.max_point().row;
 1850
 1851        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1852        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1853
 1854        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1855            let outline_items = buffer
 1856                .outline_items_containing(
 1857                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1858                    true,
 1859                    Some(style.syntax.as_ref()),
 1860                )
 1861                .into_iter()
 1862                .map(|outline_item| OutlineItem {
 1863                    depth: outline_item.depth,
 1864                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1865                    source_range_for_text: Anchor::range_in_buffer(
 1866                        *excerpt_id,
 1867                        outline_item.source_range_for_text,
 1868                    ),
 1869                    text: outline_item.text,
 1870                    highlight_ranges: outline_item.highlight_ranges,
 1871                    name_ranges: outline_item.name_ranges,
 1872                    body_range: outline_item
 1873                        .body_range
 1874                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1875                    annotation_range: outline_item
 1876                        .annotation_range
 1877                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1878                });
 1879            return Some(outline_items.collect());
 1880        }
 1881
 1882        None
 1883    }
 1884
 1885    fn new_internal(
 1886        mode: EditorMode,
 1887        multi_buffer: Entity<MultiBuffer>,
 1888        project: Option<Entity<Project>>,
 1889        display_map: Option<Entity<DisplayMap>>,
 1890        window: &mut Window,
 1891        cx: &mut Context<Self>,
 1892    ) -> Self {
 1893        debug_assert!(
 1894            display_map.is_none() || mode.is_minimap(),
 1895            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1896        );
 1897
 1898        let full_mode = mode.is_full();
 1899        let is_minimap = mode.is_minimap();
 1900        let diagnostics_max_severity = if full_mode {
 1901            EditorSettings::get_global(cx)
 1902                .diagnostics_max_severity
 1903                .unwrap_or(DiagnosticSeverity::Hint)
 1904        } else {
 1905            DiagnosticSeverity::Off
 1906        };
 1907        let style = window.text_style();
 1908        let font_size = style.font_size.to_pixels(window.rem_size());
 1909        let editor = cx.entity().downgrade();
 1910        let fold_placeholder = FoldPlaceholder {
 1911            constrain_width: false,
 1912            render: Arc::new(move |fold_id, fold_range, cx| {
 1913                let editor = editor.clone();
 1914                div()
 1915                    .id(fold_id)
 1916                    .bg(cx.theme().colors().ghost_element_background)
 1917                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1918                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1919                    .rounded_xs()
 1920                    .size_full()
 1921                    .cursor_pointer()
 1922                    .child("")
 1923                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1924                    .on_click(move |_, _window, cx| {
 1925                        editor
 1926                            .update(cx, |editor, cx| {
 1927                                editor.unfold_ranges(
 1928                                    &[fold_range.start..fold_range.end],
 1929                                    true,
 1930                                    false,
 1931                                    cx,
 1932                                );
 1933                                cx.stop_propagation();
 1934                            })
 1935                            .ok();
 1936                    })
 1937                    .into_any()
 1938            }),
 1939            merge_adjacent: true,
 1940            ..FoldPlaceholder::default()
 1941        };
 1942        let display_map = display_map.unwrap_or_else(|| {
 1943            cx.new(|cx| {
 1944                DisplayMap::new(
 1945                    multi_buffer.clone(),
 1946                    style.font(),
 1947                    font_size,
 1948                    None,
 1949                    FILE_HEADER_HEIGHT,
 1950                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1951                    fold_placeholder,
 1952                    diagnostics_max_severity,
 1953                    cx,
 1954                )
 1955            })
 1956        });
 1957
 1958        let selections = SelectionsCollection::new();
 1959
 1960        let blink_manager = cx.new(|cx| {
 1961            let mut blink_manager = BlinkManager::new(
 1962                CURSOR_BLINK_INTERVAL,
 1963                |cx| EditorSettings::get_global(cx).cursor_blink,
 1964                cx,
 1965            );
 1966            if is_minimap {
 1967                blink_manager.disable(cx);
 1968            }
 1969            blink_manager
 1970        });
 1971
 1972        let soft_wrap_mode_override =
 1973            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1974
 1975        let mut project_subscriptions = Vec::new();
 1976        if full_mode && let Some(project) = project.as_ref() {
 1977            project_subscriptions.push(cx.subscribe_in(
 1978                project,
 1979                window,
 1980                |editor, _, event, window, cx| match event {
 1981                    project::Event::RefreshCodeLens => {
 1982                        // we always query lens with actions, without storing them, always refreshing them
 1983                    }
 1984                    project::Event::RefreshInlayHints {
 1985                        server_id,
 1986                        request_id,
 1987                    } => {
 1988                        editor.refresh_inlay_hints(
 1989                            InlayHintRefreshReason::RefreshRequested {
 1990                                server_id: *server_id,
 1991                                request_id: *request_id,
 1992                            },
 1993                            cx,
 1994                        );
 1995                    }
 1996                    project::Event::LanguageServerRemoved(..) => {
 1997                        if editor.tasks_update_task.is_none() {
 1998                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1999                        }
 2000                        editor.registered_buffers.clear();
 2001                        editor.register_visible_buffers(cx);
 2002                    }
 2003                    project::Event::LanguageServerAdded(..) => {
 2004                        if editor.tasks_update_task.is_none() {
 2005                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2006                        }
 2007                    }
 2008                    project::Event::SnippetEdit(id, snippet_edits) => {
 2009                        // todo(lw): Non singletons
 2010                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2011                            let snapshot = buffer.read(cx).snapshot();
 2012                            let focus_handle = editor.focus_handle(cx);
 2013                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2014                                for (range, snippet) in snippet_edits {
 2015                                    let buffer_range =
 2016                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2017                                    editor
 2018                                        .insert_snippet(
 2019                                            &[MultiBufferOffset(buffer_range.start)
 2020                                                ..MultiBufferOffset(buffer_range.end)],
 2021                                            snippet.clone(),
 2022                                            window,
 2023                                            cx,
 2024                                        )
 2025                                        .ok();
 2026                                }
 2027                            }
 2028                        }
 2029                    }
 2030                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2031                        let buffer_id = *buffer_id;
 2032                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2033                            editor.register_buffer(buffer_id, cx);
 2034                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2035                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2036                            refresh_linked_ranges(editor, window, cx);
 2037                            editor.refresh_code_actions(window, cx);
 2038                            editor.refresh_document_highlights(cx);
 2039                        }
 2040                    }
 2041
 2042                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2043                        let Some(workspace) = editor.workspace() else {
 2044                            return;
 2045                        };
 2046                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2047                        else {
 2048                            return;
 2049                        };
 2050
 2051                        if active_editor.entity_id() == cx.entity_id() {
 2052                            let entity_id = cx.entity_id();
 2053                            workspace.update(cx, |this, cx| {
 2054                                this.panes_mut()
 2055                                    .iter_mut()
 2056                                    .filter(|pane| pane.entity_id() != entity_id)
 2057                                    .for_each(|p| {
 2058                                        p.update(cx, |pane, _| {
 2059                                            pane.nav_history_mut().rename_item(
 2060                                                entity_id,
 2061                                                project_path.clone(),
 2062                                                abs_path.clone().into(),
 2063                                            );
 2064                                        })
 2065                                    });
 2066                            });
 2067
 2068                            Self::open_transaction_for_hidden_buffers(
 2069                                workspace,
 2070                                transaction.clone(),
 2071                                "Rename".to_string(),
 2072                                window,
 2073                                cx,
 2074                            );
 2075                        }
 2076                    }
 2077
 2078                    project::Event::WorkspaceEditApplied(transaction) => {
 2079                        let Some(workspace) = editor.workspace() else {
 2080                            return;
 2081                        };
 2082                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2083                        else {
 2084                            return;
 2085                        };
 2086
 2087                        if active_editor.entity_id() == cx.entity_id() {
 2088                            Self::open_transaction_for_hidden_buffers(
 2089                                workspace,
 2090                                transaction.clone(),
 2091                                "LSP Edit".to_string(),
 2092                                window,
 2093                                cx,
 2094                            );
 2095                        }
 2096                    }
 2097
 2098                    _ => {}
 2099                },
 2100            ));
 2101            if let Some(task_inventory) = project
 2102                .read(cx)
 2103                .task_store()
 2104                .read(cx)
 2105                .task_inventory()
 2106                .cloned()
 2107            {
 2108                project_subscriptions.push(cx.observe_in(
 2109                    &task_inventory,
 2110                    window,
 2111                    |editor, _, window, cx| {
 2112                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2113                    },
 2114                ));
 2115            };
 2116
 2117            project_subscriptions.push(cx.subscribe_in(
 2118                &project.read(cx).breakpoint_store(),
 2119                window,
 2120                |editor, _, event, window, cx| match event {
 2121                    BreakpointStoreEvent::ClearDebugLines => {
 2122                        editor.clear_row_highlights::<ActiveDebugLine>();
 2123                        editor.refresh_inline_values(cx);
 2124                    }
 2125                    BreakpointStoreEvent::SetDebugLine => {
 2126                        if editor.go_to_active_debug_line(window, cx) {
 2127                            cx.stop_propagation();
 2128                        }
 2129
 2130                        editor.refresh_inline_values(cx);
 2131                    }
 2132                    _ => {}
 2133                },
 2134            ));
 2135            let git_store = project.read(cx).git_store().clone();
 2136            let project = project.clone();
 2137            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2138                if let GitStoreEvent::RepositoryAdded = event {
 2139                    this.load_diff_task = Some(
 2140                        update_uncommitted_diff_for_buffer(
 2141                            cx.entity(),
 2142                            &project,
 2143                            this.buffer.read(cx).all_buffers(),
 2144                            this.buffer.clone(),
 2145                            cx,
 2146                        )
 2147                        .shared(),
 2148                    );
 2149                }
 2150            }));
 2151        }
 2152
 2153        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2154
 2155        let inlay_hint_settings =
 2156            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2157        let focus_handle = cx.focus_handle();
 2158        if !is_minimap {
 2159            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2160                .detach();
 2161            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2162                .detach();
 2163            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2164                .detach();
 2165            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2166                .detach();
 2167            cx.observe_pending_input(window, Self::observe_pending_input)
 2168                .detach();
 2169        }
 2170
 2171        let show_indent_guides =
 2172            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2173                Some(false)
 2174            } else {
 2175                None
 2176            };
 2177
 2178        let breakpoint_store = match (&mode, project.as_ref()) {
 2179            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2180            _ => None,
 2181        };
 2182
 2183        let mut code_action_providers = Vec::new();
 2184        let mut load_uncommitted_diff = None;
 2185        if let Some(project) = project.clone() {
 2186            load_uncommitted_diff = Some(
 2187                update_uncommitted_diff_for_buffer(
 2188                    cx.entity(),
 2189                    &project,
 2190                    multi_buffer.read(cx).all_buffers(),
 2191                    multi_buffer.clone(),
 2192                    cx,
 2193                )
 2194                .shared(),
 2195            );
 2196            code_action_providers.push(Rc::new(project) as Rc<_>);
 2197        }
 2198
 2199        let mut editor = Self {
 2200            focus_handle,
 2201            show_cursor_when_unfocused: false,
 2202            last_focused_descendant: None,
 2203            buffer: multi_buffer.clone(),
 2204            display_map: display_map.clone(),
 2205            placeholder_display_map: None,
 2206            selections,
 2207            scroll_manager: ScrollManager::new(cx),
 2208            columnar_selection_state: None,
 2209            add_selections_state: None,
 2210            select_next_state: None,
 2211            select_prev_state: None,
 2212            selection_history: SelectionHistory::default(),
 2213            defer_selection_effects: false,
 2214            deferred_selection_effects_state: None,
 2215            autoclose_regions: Vec::new(),
 2216            snippet_stack: InvalidationStack::default(),
 2217            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2218            ime_transaction: None,
 2219            active_diagnostics: ActiveDiagnostic::None,
 2220            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2221            inline_diagnostics_update: Task::ready(()),
 2222            inline_diagnostics: Vec::new(),
 2223            soft_wrap_mode_override,
 2224            diagnostics_max_severity,
 2225            hard_wrap: None,
 2226            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2227            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2228            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2229            project,
 2230            blink_manager: blink_manager.clone(),
 2231            show_local_selections: true,
 2232            show_scrollbars: ScrollbarAxes {
 2233                horizontal: full_mode,
 2234                vertical: full_mode,
 2235            },
 2236            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2237            offset_content: !matches!(mode, EditorMode::SingleLine),
 2238            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2239            show_gutter: full_mode,
 2240            show_line_numbers: (!full_mode).then_some(false),
 2241            use_relative_line_numbers: None,
 2242            disable_expand_excerpt_buttons: !full_mode,
 2243            show_git_diff_gutter: None,
 2244            show_code_actions: None,
 2245            show_runnables: None,
 2246            show_breakpoints: None,
 2247            show_wrap_guides: None,
 2248            show_indent_guides,
 2249            buffers_with_disabled_indent_guides: HashSet::default(),
 2250            highlight_order: 0,
 2251            highlighted_rows: HashMap::default(),
 2252            background_highlights: HashMap::default(),
 2253            gutter_highlights: HashMap::default(),
 2254            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2255            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2256            nav_history: None,
 2257            context_menu: RefCell::new(None),
 2258            context_menu_options: None,
 2259            mouse_context_menu: None,
 2260            completion_tasks: Vec::new(),
 2261            inline_blame_popover: None,
 2262            inline_blame_popover_show_task: None,
 2263            signature_help_state: SignatureHelpState::default(),
 2264            auto_signature_help: None,
 2265            find_all_references_task_sources: Vec::new(),
 2266            next_completion_id: 0,
 2267            next_inlay_id: 0,
 2268            code_action_providers,
 2269            available_code_actions: None,
 2270            code_actions_task: None,
 2271            quick_selection_highlight_task: None,
 2272            debounced_selection_highlight_task: None,
 2273            document_highlights_task: None,
 2274            linked_editing_range_task: None,
 2275            pending_rename: None,
 2276            searchable: !is_minimap,
 2277            cursor_shape: EditorSettings::get_global(cx)
 2278                .cursor_shape
 2279                .unwrap_or_default(),
 2280            cursor_offset_on_selection: false,
 2281            current_line_highlight: None,
 2282            autoindent_mode: Some(AutoindentMode::EachLine),
 2283            collapse_matches: false,
 2284            workspace: None,
 2285            input_enabled: !is_minimap,
 2286            use_modal_editing: full_mode,
 2287            read_only: is_minimap,
 2288            use_autoclose: true,
 2289            use_auto_surround: true,
 2290            auto_replace_emoji_shortcode: false,
 2291            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2292            leader_id: None,
 2293            remote_id: None,
 2294            hover_state: HoverState::default(),
 2295            pending_mouse_down: None,
 2296            prev_pressure_stage: None,
 2297            hovered_link_state: None,
 2298            edit_prediction_provider: None,
 2299            active_edit_prediction: None,
 2300            stale_edit_prediction_in_menu: None,
 2301            edit_prediction_preview: EditPredictionPreview::Inactive {
 2302                released_too_fast: false,
 2303            },
 2304            inline_diagnostics_enabled: full_mode,
 2305            diagnostics_enabled: full_mode,
 2306            word_completions_enabled: full_mode,
 2307            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2308            gutter_hovered: false,
 2309            pixel_position_of_newest_cursor: None,
 2310            last_bounds: None,
 2311            last_position_map: None,
 2312            expect_bounds_change: None,
 2313            gutter_dimensions: GutterDimensions::default(),
 2314            style: None,
 2315            show_cursor_names: false,
 2316            hovered_cursors: HashMap::default(),
 2317            next_editor_action_id: EditorActionId::default(),
 2318            editor_actions: Rc::default(),
 2319            edit_predictions_hidden_for_vim_mode: false,
 2320            show_edit_predictions_override: None,
 2321            show_completions_on_input_override: None,
 2322            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2323            edit_prediction_settings: EditPredictionSettings::Disabled,
 2324            edit_prediction_indent_conflict: false,
 2325            edit_prediction_requires_modifier_in_indent_conflict: true,
 2326            custom_context_menu: None,
 2327            show_git_blame_gutter: false,
 2328            show_git_blame_inline: false,
 2329            show_selection_menu: None,
 2330            show_git_blame_inline_delay_task: None,
 2331            git_blame_inline_enabled: full_mode
 2332                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2333            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2334            buffer_serialization: is_minimap.not().then(|| {
 2335                BufferSerialization::new(
 2336                    ProjectSettings::get_global(cx)
 2337                        .session
 2338                        .restore_unsaved_buffers,
 2339                )
 2340            }),
 2341            blame: None,
 2342            blame_subscription: None,
 2343            tasks: BTreeMap::default(),
 2344
 2345            breakpoint_store,
 2346            gutter_breakpoint_indicator: (None, None),
 2347            hovered_diff_hunk_row: None,
 2348            _subscriptions: (!is_minimap)
 2349                .then(|| {
 2350                    vec![
 2351                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2352                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2353                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2354                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2355                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2356                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2357                        cx.observe_window_activation(window, |editor, window, cx| {
 2358                            let active = window.is_window_active();
 2359                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2360                                if active {
 2361                                    blink_manager.enable(cx);
 2362                                } else {
 2363                                    blink_manager.disable(cx);
 2364                                }
 2365                            });
 2366                            if active {
 2367                                editor.show_mouse_cursor(cx);
 2368                            }
 2369                        }),
 2370                    ]
 2371                })
 2372                .unwrap_or_default(),
 2373            tasks_update_task: None,
 2374            pull_diagnostics_task: Task::ready(()),
 2375            pull_diagnostics_background_task: Task::ready(()),
 2376            colors: None,
 2377            refresh_colors_task: Task::ready(()),
 2378            inlay_hints: None,
 2379            next_color_inlay_id: 0,
 2380            post_scroll_update: Task::ready(()),
 2381            linked_edit_ranges: Default::default(),
 2382            in_project_search: false,
 2383            previous_search_ranges: None,
 2384            breadcrumb_header: None,
 2385            focused_block: None,
 2386            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2387            addons: HashMap::default(),
 2388            registered_buffers: HashMap::default(),
 2389            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2390            selection_mark_mode: false,
 2391            toggle_fold_multiple_buffers: Task::ready(()),
 2392            serialize_selections: Task::ready(()),
 2393            serialize_folds: Task::ready(()),
 2394            text_style_refinement: None,
 2395            load_diff_task: load_uncommitted_diff,
 2396            temporary_diff_override: false,
 2397            mouse_cursor_hidden: false,
 2398            minimap: None,
 2399            hide_mouse_mode: EditorSettings::get_global(cx)
 2400                .hide_mouse
 2401                .unwrap_or_default(),
 2402            change_list: ChangeList::new(),
 2403            mode,
 2404            selection_drag_state: SelectionDragState::None,
 2405            folding_newlines: Task::ready(()),
 2406            lookup_key: None,
 2407            select_next_is_case_sensitive: None,
 2408            applicable_language_settings: HashMap::default(),
 2409            accent_data: None,
 2410            fetched_tree_sitter_chunks: HashMap::default(),
 2411            use_base_text_line_numbers: false,
 2412        };
 2413
 2414        if is_minimap {
 2415            return editor;
 2416        }
 2417
 2418        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2419        editor.accent_data = editor.fetch_accent_data(cx);
 2420
 2421        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2422            editor
 2423                ._subscriptions
 2424                .push(cx.observe(breakpoints, |_, _, cx| {
 2425                    cx.notify();
 2426                }));
 2427        }
 2428        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2429        editor._subscriptions.extend(project_subscriptions);
 2430
 2431        editor._subscriptions.push(cx.subscribe_in(
 2432            &cx.entity(),
 2433            window,
 2434            |editor, _, e: &EditorEvent, window, cx| match e {
 2435                EditorEvent::ScrollPositionChanged { local, .. } => {
 2436                    if *local {
 2437                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2438                        editor.inline_blame_popover.take();
 2439                        let new_anchor = editor.scroll_manager.anchor();
 2440                        let snapshot = editor.snapshot(window, cx);
 2441                        editor.update_restoration_data(cx, move |data| {
 2442                            data.scroll_position = (
 2443                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2444                                new_anchor.offset,
 2445                            );
 2446                        });
 2447
 2448                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2449                            cx.background_executor()
 2450                                .timer(Duration::from_millis(50))
 2451                                .await;
 2452                            editor
 2453                                .update_in(cx, |editor, window, cx| {
 2454                                    editor.register_visible_buffers(cx);
 2455                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2456                                    editor.refresh_inlay_hints(
 2457                                        InlayHintRefreshReason::NewLinesShown,
 2458                                        cx,
 2459                                    );
 2460                                    editor.colorize_brackets(false, cx);
 2461                                })
 2462                                .ok();
 2463                        });
 2464                    }
 2465                }
 2466                EditorEvent::Edited { .. } => {
 2467                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2468                        .map(|vim_mode| vim_mode.0)
 2469                        .unwrap_or(false);
 2470                    if !vim_mode {
 2471                        let display_map = editor.display_snapshot(cx);
 2472                        let selections = editor.selections.all_adjusted_display(&display_map);
 2473                        let pop_state = editor
 2474                            .change_list
 2475                            .last()
 2476                            .map(|previous| {
 2477                                previous.len() == selections.len()
 2478                                    && previous.iter().enumerate().all(|(ix, p)| {
 2479                                        p.to_display_point(&display_map).row()
 2480                                            == selections[ix].head().row()
 2481                                    })
 2482                            })
 2483                            .unwrap_or(false);
 2484                        let new_positions = selections
 2485                            .into_iter()
 2486                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2487                            .collect();
 2488                        editor
 2489                            .change_list
 2490                            .push_to_change_list(pop_state, new_positions);
 2491                    }
 2492                }
 2493                _ => (),
 2494            },
 2495        ));
 2496
 2497        if let Some(dap_store) = editor
 2498            .project
 2499            .as_ref()
 2500            .map(|project| project.read(cx).dap_store())
 2501        {
 2502            let weak_editor = cx.weak_entity();
 2503
 2504            editor
 2505                ._subscriptions
 2506                .push(
 2507                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2508                        let session_entity = cx.entity();
 2509                        weak_editor
 2510                            .update(cx, |editor, cx| {
 2511                                editor._subscriptions.push(
 2512                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2513                                );
 2514                            })
 2515                            .ok();
 2516                    }),
 2517                );
 2518
 2519            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2520                editor
 2521                    ._subscriptions
 2522                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2523            }
 2524        }
 2525
 2526        // skip adding the initial selection to selection history
 2527        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2528        editor.end_selection(window, cx);
 2529        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2530
 2531        editor.scroll_manager.show_scrollbars(window, cx);
 2532        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2533
 2534        if full_mode {
 2535            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2536            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2537
 2538            if editor.git_blame_inline_enabled {
 2539                editor.start_git_blame_inline(false, window, cx);
 2540            }
 2541
 2542            editor.go_to_active_debug_line(window, cx);
 2543
 2544            editor.minimap =
 2545                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2546            editor.colors = Some(LspColorData::new(cx));
 2547            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2548
 2549            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2550                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2551            }
 2552            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2553        }
 2554
 2555        editor
 2556    }
 2557
 2558    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2559        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2560    }
 2561
 2562    pub fn deploy_mouse_context_menu(
 2563        &mut self,
 2564        position: gpui::Point<Pixels>,
 2565        context_menu: Entity<ContextMenu>,
 2566        window: &mut Window,
 2567        cx: &mut Context<Self>,
 2568    ) {
 2569        self.mouse_context_menu = Some(MouseContextMenu::new(
 2570            self,
 2571            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2572            context_menu,
 2573            window,
 2574            cx,
 2575        ));
 2576    }
 2577
 2578    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2579        self.mouse_context_menu
 2580            .as_ref()
 2581            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2582    }
 2583
 2584    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2585        if self
 2586            .selections
 2587            .pending_anchor()
 2588            .is_some_and(|pending_selection| {
 2589                let snapshot = self.buffer().read(cx).snapshot(cx);
 2590                pending_selection.range().includes(range, &snapshot)
 2591            })
 2592        {
 2593            return true;
 2594        }
 2595
 2596        self.selections
 2597            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2598            .into_iter()
 2599            .any(|selection| {
 2600                // This is needed to cover a corner case, if we just check for an existing
 2601                // selection in the fold range, having a cursor at the start of the fold
 2602                // marks it as selected. Non-empty selections don't cause this.
 2603                let length = selection.end - selection.start;
 2604                length > 0
 2605            })
 2606    }
 2607
 2608    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2609        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2610    }
 2611
 2612    fn key_context_internal(
 2613        &self,
 2614        has_active_edit_prediction: bool,
 2615        window: &mut Window,
 2616        cx: &mut App,
 2617    ) -> KeyContext {
 2618        let mut key_context = KeyContext::new_with_defaults();
 2619        key_context.add("Editor");
 2620        let mode = match self.mode {
 2621            EditorMode::SingleLine => "single_line",
 2622            EditorMode::AutoHeight { .. } => "auto_height",
 2623            EditorMode::Minimap { .. } => "minimap",
 2624            EditorMode::Full { .. } => "full",
 2625        };
 2626
 2627        if EditorSettings::jupyter_enabled(cx) {
 2628            key_context.add("jupyter");
 2629        }
 2630
 2631        key_context.set("mode", mode);
 2632        if self.pending_rename.is_some() {
 2633            key_context.add("renaming");
 2634        }
 2635
 2636        if let Some(snippet_stack) = self.snippet_stack.last() {
 2637            key_context.add("in_snippet");
 2638
 2639            if snippet_stack.active_index > 0 {
 2640                key_context.add("has_previous_tabstop");
 2641            }
 2642
 2643            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2644                key_context.add("has_next_tabstop");
 2645            }
 2646        }
 2647
 2648        match self.context_menu.borrow().as_ref() {
 2649            Some(CodeContextMenu::Completions(menu)) => {
 2650                if menu.visible() {
 2651                    key_context.add("menu");
 2652                    key_context.add("showing_completions");
 2653                }
 2654            }
 2655            Some(CodeContextMenu::CodeActions(menu)) => {
 2656                if menu.visible() {
 2657                    key_context.add("menu");
 2658                    key_context.add("showing_code_actions")
 2659                }
 2660            }
 2661            None => {}
 2662        }
 2663
 2664        if self.signature_help_state.has_multiple_signatures() {
 2665            key_context.add("showing_signature_help");
 2666        }
 2667
 2668        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2669        if !self.focus_handle(cx).contains_focused(window, cx)
 2670            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2671        {
 2672            for addon in self.addons.values() {
 2673                addon.extend_key_context(&mut key_context, cx)
 2674            }
 2675        }
 2676
 2677        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2678            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2679                Some(
 2680                    file.full_path(cx)
 2681                        .extension()?
 2682                        .to_string_lossy()
 2683                        .into_owned(),
 2684                )
 2685            }) {
 2686                key_context.set("extension", extension);
 2687            }
 2688        } else {
 2689            key_context.add("multibuffer");
 2690        }
 2691
 2692        if has_active_edit_prediction {
 2693            if self.edit_prediction_in_conflict() {
 2694                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2695            } else {
 2696                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2697                key_context.add("copilot_suggestion");
 2698            }
 2699        }
 2700
 2701        if self.selection_mark_mode {
 2702            key_context.add("selection_mode");
 2703        }
 2704
 2705        let disjoint = self.selections.disjoint_anchors();
 2706        let snapshot = self.snapshot(window, cx);
 2707        let snapshot = snapshot.buffer_snapshot();
 2708        if self.mode == EditorMode::SingleLine
 2709            && let [selection] = disjoint
 2710            && selection.start == selection.end
 2711            && selection.end.to_offset(snapshot) == snapshot.len()
 2712        {
 2713            key_context.add("end_of_input");
 2714        }
 2715
 2716        if self.has_any_expanded_diff_hunks(cx) {
 2717            key_context.add("diffs_expanded");
 2718        }
 2719
 2720        key_context
 2721    }
 2722
 2723    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2724        self.last_bounds.as_ref()
 2725    }
 2726
 2727    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2728        if self.mouse_cursor_hidden {
 2729            self.mouse_cursor_hidden = false;
 2730            cx.notify();
 2731        }
 2732    }
 2733
 2734    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2735        let hide_mouse_cursor = match origin {
 2736            HideMouseCursorOrigin::TypingAction => {
 2737                matches!(
 2738                    self.hide_mouse_mode,
 2739                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2740                )
 2741            }
 2742            HideMouseCursorOrigin::MovementAction => {
 2743                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2744            }
 2745        };
 2746        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2747            self.mouse_cursor_hidden = hide_mouse_cursor;
 2748            cx.notify();
 2749        }
 2750    }
 2751
 2752    pub fn edit_prediction_in_conflict(&self) -> bool {
 2753        if !self.show_edit_predictions_in_menu() {
 2754            return false;
 2755        }
 2756
 2757        let showing_completions = self
 2758            .context_menu
 2759            .borrow()
 2760            .as_ref()
 2761            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2762
 2763        showing_completions
 2764            || self.edit_prediction_requires_modifier()
 2765            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2766            // bindings to insert tab characters.
 2767            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2768    }
 2769
 2770    pub fn accept_edit_prediction_keybind(
 2771        &self,
 2772        granularity: EditPredictionGranularity,
 2773        window: &mut Window,
 2774        cx: &mut App,
 2775    ) -> AcceptEditPredictionBinding {
 2776        let key_context = self.key_context_internal(true, window, cx);
 2777        let in_conflict = self.edit_prediction_in_conflict();
 2778
 2779        let bindings =
 2780            match granularity {
 2781                EditPredictionGranularity::Word => window
 2782                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2783                EditPredictionGranularity::Line => window
 2784                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2785                EditPredictionGranularity::Full => {
 2786                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2787                }
 2788            };
 2789
 2790        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2791            !in_conflict
 2792                || binding
 2793                    .keystrokes()
 2794                    .first()
 2795                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2796        }))
 2797    }
 2798
 2799    pub fn new_file(
 2800        workspace: &mut Workspace,
 2801        _: &workspace::NewFile,
 2802        window: &mut Window,
 2803        cx: &mut Context<Workspace>,
 2804    ) {
 2805        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2806            "Failed to create buffer",
 2807            window,
 2808            cx,
 2809            |e, _, _| match e.error_code() {
 2810                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2811                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2812                e.error_tag("required").unwrap_or("the latest version")
 2813            )),
 2814                _ => None,
 2815            },
 2816        );
 2817    }
 2818
 2819    pub fn new_in_workspace(
 2820        workspace: &mut Workspace,
 2821        window: &mut Window,
 2822        cx: &mut Context<Workspace>,
 2823    ) -> Task<Result<Entity<Editor>>> {
 2824        let project = workspace.project().clone();
 2825        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2826
 2827        cx.spawn_in(window, async move |workspace, cx| {
 2828            let buffer = create.await?;
 2829            workspace.update_in(cx, |workspace, window, cx| {
 2830                let editor =
 2831                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2832                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2833                editor
 2834            })
 2835        })
 2836    }
 2837
 2838    fn new_file_vertical(
 2839        workspace: &mut Workspace,
 2840        _: &workspace::NewFileSplitVertical,
 2841        window: &mut Window,
 2842        cx: &mut Context<Workspace>,
 2843    ) {
 2844        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2845    }
 2846
 2847    fn new_file_horizontal(
 2848        workspace: &mut Workspace,
 2849        _: &workspace::NewFileSplitHorizontal,
 2850        window: &mut Window,
 2851        cx: &mut Context<Workspace>,
 2852    ) {
 2853        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2854    }
 2855
 2856    fn new_file_split(
 2857        workspace: &mut Workspace,
 2858        action: &workspace::NewFileSplit,
 2859        window: &mut Window,
 2860        cx: &mut Context<Workspace>,
 2861    ) {
 2862        Self::new_file_in_direction(workspace, action.0, window, cx)
 2863    }
 2864
 2865    fn new_file_in_direction(
 2866        workspace: &mut Workspace,
 2867        direction: SplitDirection,
 2868        window: &mut Window,
 2869        cx: &mut Context<Workspace>,
 2870    ) {
 2871        let project = workspace.project().clone();
 2872        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2873
 2874        cx.spawn_in(window, async move |workspace, cx| {
 2875            let buffer = create.await?;
 2876            workspace.update_in(cx, move |workspace, window, cx| {
 2877                workspace.split_item(
 2878                    direction,
 2879                    Box::new(
 2880                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2881                    ),
 2882                    window,
 2883                    cx,
 2884                )
 2885            })?;
 2886            anyhow::Ok(())
 2887        })
 2888        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2889            match e.error_code() {
 2890                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2891                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2892                e.error_tag("required").unwrap_or("the latest version")
 2893            )),
 2894                _ => None,
 2895            }
 2896        });
 2897    }
 2898
 2899    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2900        self.leader_id
 2901    }
 2902
 2903    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2904        &self.buffer
 2905    }
 2906
 2907    pub fn project(&self) -> Option<&Entity<Project>> {
 2908        self.project.as_ref()
 2909    }
 2910
 2911    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2912        self.workspace.as_ref()?.0.upgrade()
 2913    }
 2914
 2915    /// Returns the workspace serialization ID if this editor should be serialized.
 2916    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2917        self.workspace
 2918            .as_ref()
 2919            .filter(|_| self.should_serialize_buffer())
 2920            .and_then(|workspace| workspace.1)
 2921    }
 2922
 2923    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2924        self.buffer().read(cx).title(cx)
 2925    }
 2926
 2927    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2928        let git_blame_gutter_max_author_length = self
 2929            .render_git_blame_gutter(cx)
 2930            .then(|| {
 2931                if let Some(blame) = self.blame.as_ref() {
 2932                    let max_author_length =
 2933                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2934                    Some(max_author_length)
 2935                } else {
 2936                    None
 2937                }
 2938            })
 2939            .flatten();
 2940
 2941        EditorSnapshot {
 2942            mode: self.mode.clone(),
 2943            show_gutter: self.show_gutter,
 2944            offset_content: self.offset_content,
 2945            show_line_numbers: self.show_line_numbers,
 2946            show_git_diff_gutter: self.show_git_diff_gutter,
 2947            show_code_actions: self.show_code_actions,
 2948            show_runnables: self.show_runnables,
 2949            show_breakpoints: self.show_breakpoints,
 2950            git_blame_gutter_max_author_length,
 2951            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2952            placeholder_display_snapshot: self
 2953                .placeholder_display_map
 2954                .as_ref()
 2955                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2956            scroll_anchor: self.scroll_manager.anchor(),
 2957            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2958            is_focused: self.focus_handle.is_focused(window),
 2959            current_line_highlight: self
 2960                .current_line_highlight
 2961                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2962            gutter_hovered: self.gutter_hovered,
 2963        }
 2964    }
 2965
 2966    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2967        self.buffer.read(cx).language_at(point, cx)
 2968    }
 2969
 2970    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2971        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2972    }
 2973
 2974    pub fn active_excerpt(
 2975        &self,
 2976        cx: &App,
 2977    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2978        self.buffer
 2979            .read(cx)
 2980            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2981    }
 2982
 2983    pub fn mode(&self) -> &EditorMode {
 2984        &self.mode
 2985    }
 2986
 2987    pub fn set_mode(&mut self, mode: EditorMode) {
 2988        self.mode = mode;
 2989    }
 2990
 2991    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2992        self.collaboration_hub.as_deref()
 2993    }
 2994
 2995    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2996        self.collaboration_hub = Some(hub);
 2997    }
 2998
 2999    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3000        self.in_project_search = in_project_search;
 3001    }
 3002
 3003    pub fn set_custom_context_menu(
 3004        &mut self,
 3005        f: impl 'static
 3006        + Fn(
 3007            &mut Self,
 3008            DisplayPoint,
 3009            &mut Window,
 3010            &mut Context<Self>,
 3011        ) -> Option<Entity<ui::ContextMenu>>,
 3012    ) {
 3013        self.custom_context_menu = Some(Box::new(f))
 3014    }
 3015
 3016    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3017        self.completion_provider = provider;
 3018    }
 3019
 3020    #[cfg(any(test, feature = "test-support"))]
 3021    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3022        self.completion_provider.clone()
 3023    }
 3024
 3025    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3026        self.semantics_provider.clone()
 3027    }
 3028
 3029    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3030        self.semantics_provider = provider;
 3031    }
 3032
 3033    pub fn set_edit_prediction_provider<T>(
 3034        &mut self,
 3035        provider: Option<Entity<T>>,
 3036        window: &mut Window,
 3037        cx: &mut Context<Self>,
 3038    ) where
 3039        T: EditPredictionDelegate,
 3040    {
 3041        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3042            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3043                if this.focus_handle.is_focused(window) {
 3044                    this.update_visible_edit_prediction(window, cx);
 3045                }
 3046            }),
 3047            provider: Arc::new(provider),
 3048        });
 3049        self.update_edit_prediction_settings(cx);
 3050        self.refresh_edit_prediction(false, false, window, cx);
 3051    }
 3052
 3053    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3054        self.placeholder_display_map
 3055            .as_ref()
 3056            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3057    }
 3058
 3059    pub fn set_placeholder_text(
 3060        &mut self,
 3061        placeholder_text: &str,
 3062        window: &mut Window,
 3063        cx: &mut Context<Self>,
 3064    ) {
 3065        let multibuffer = cx
 3066            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3067
 3068        let style = window.text_style();
 3069
 3070        self.placeholder_display_map = Some(cx.new(|cx| {
 3071            DisplayMap::new(
 3072                multibuffer,
 3073                style.font(),
 3074                style.font_size.to_pixels(window.rem_size()),
 3075                None,
 3076                FILE_HEADER_HEIGHT,
 3077                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3078                Default::default(),
 3079                DiagnosticSeverity::Off,
 3080                cx,
 3081            )
 3082        }));
 3083        cx.notify();
 3084    }
 3085
 3086    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3087        self.cursor_shape = cursor_shape;
 3088
 3089        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3090        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3091
 3092        cx.notify();
 3093    }
 3094
 3095    pub fn cursor_shape(&self) -> CursorShape {
 3096        self.cursor_shape
 3097    }
 3098
 3099    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3100        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3101    }
 3102
 3103    pub fn set_current_line_highlight(
 3104        &mut self,
 3105        current_line_highlight: Option<CurrentLineHighlight>,
 3106    ) {
 3107        self.current_line_highlight = current_line_highlight;
 3108    }
 3109
 3110    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3111        self.collapse_matches = collapse_matches;
 3112    }
 3113
 3114    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3115        if self.collapse_matches {
 3116            return range.start..range.start;
 3117        }
 3118        range.clone()
 3119    }
 3120
 3121    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3122        self.display_map.read(cx).clip_at_line_ends
 3123    }
 3124
 3125    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3126        if self.display_map.read(cx).clip_at_line_ends != clip {
 3127            self.display_map
 3128                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3129        }
 3130    }
 3131
 3132    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3133        self.input_enabled = input_enabled;
 3134    }
 3135
 3136    pub fn set_edit_predictions_hidden_for_vim_mode(
 3137        &mut self,
 3138        hidden: bool,
 3139        window: &mut Window,
 3140        cx: &mut Context<Self>,
 3141    ) {
 3142        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3143            self.edit_predictions_hidden_for_vim_mode = hidden;
 3144            if hidden {
 3145                self.update_visible_edit_prediction(window, cx);
 3146            } else {
 3147                self.refresh_edit_prediction(true, false, window, cx);
 3148            }
 3149        }
 3150    }
 3151
 3152    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3153        self.menu_edit_predictions_policy = value;
 3154    }
 3155
 3156    pub fn set_autoindent(&mut self, autoindent: bool) {
 3157        if autoindent {
 3158            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3159        } else {
 3160            self.autoindent_mode = None;
 3161        }
 3162    }
 3163
 3164    pub fn read_only(&self, cx: &App) -> bool {
 3165        self.read_only || self.buffer.read(cx).read_only()
 3166    }
 3167
 3168    pub fn set_read_only(&mut self, read_only: bool) {
 3169        self.read_only = read_only;
 3170    }
 3171
 3172    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3173        self.use_autoclose = autoclose;
 3174    }
 3175
 3176    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3177        self.use_auto_surround = auto_surround;
 3178    }
 3179
 3180    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3181        self.auto_replace_emoji_shortcode = auto_replace;
 3182    }
 3183
 3184    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3185        self.buffer_serialization = should_serialize.then(|| {
 3186            BufferSerialization::new(
 3187                ProjectSettings::get_global(cx)
 3188                    .session
 3189                    .restore_unsaved_buffers,
 3190            )
 3191        })
 3192    }
 3193
 3194    fn should_serialize_buffer(&self) -> bool {
 3195        self.buffer_serialization.is_some()
 3196    }
 3197
 3198    pub fn toggle_edit_predictions(
 3199        &mut self,
 3200        _: &ToggleEditPrediction,
 3201        window: &mut Window,
 3202        cx: &mut Context<Self>,
 3203    ) {
 3204        if self.show_edit_predictions_override.is_some() {
 3205            self.set_show_edit_predictions(None, window, cx);
 3206        } else {
 3207            let show_edit_predictions = !self.edit_predictions_enabled();
 3208            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3209        }
 3210    }
 3211
 3212    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3213        self.show_completions_on_input_override = show_completions_on_input;
 3214    }
 3215
 3216    pub fn set_show_edit_predictions(
 3217        &mut self,
 3218        show_edit_predictions: Option<bool>,
 3219        window: &mut Window,
 3220        cx: &mut Context<Self>,
 3221    ) {
 3222        self.show_edit_predictions_override = show_edit_predictions;
 3223        self.update_edit_prediction_settings(cx);
 3224
 3225        if let Some(false) = show_edit_predictions {
 3226            self.discard_edit_prediction(false, cx);
 3227        } else {
 3228            self.refresh_edit_prediction(false, true, window, cx);
 3229        }
 3230    }
 3231
 3232    fn edit_predictions_disabled_in_scope(
 3233        &self,
 3234        buffer: &Entity<Buffer>,
 3235        buffer_position: language::Anchor,
 3236        cx: &App,
 3237    ) -> bool {
 3238        let snapshot = buffer.read(cx).snapshot();
 3239        let settings = snapshot.settings_at(buffer_position, cx);
 3240
 3241        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3242            return false;
 3243        };
 3244
 3245        scope.override_name().is_some_and(|scope_name| {
 3246            settings
 3247                .edit_predictions_disabled_in
 3248                .iter()
 3249                .any(|s| s == scope_name)
 3250        })
 3251    }
 3252
 3253    pub fn set_use_modal_editing(&mut self, to: bool) {
 3254        self.use_modal_editing = to;
 3255    }
 3256
 3257    pub fn use_modal_editing(&self) -> bool {
 3258        self.use_modal_editing
 3259    }
 3260
 3261    fn selections_did_change(
 3262        &mut self,
 3263        local: bool,
 3264        old_cursor_position: &Anchor,
 3265        effects: SelectionEffects,
 3266        window: &mut Window,
 3267        cx: &mut Context<Self>,
 3268    ) {
 3269        window.invalidate_character_coordinates();
 3270
 3271        // Copy selections to primary selection buffer
 3272        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3273        if local {
 3274            let selections = self
 3275                .selections
 3276                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3277            let buffer_handle = self.buffer.read(cx).read(cx);
 3278
 3279            let mut text = String::new();
 3280            for (index, selection) in selections.iter().enumerate() {
 3281                let text_for_selection = buffer_handle
 3282                    .text_for_range(selection.start..selection.end)
 3283                    .collect::<String>();
 3284
 3285                text.push_str(&text_for_selection);
 3286                if index != selections.len() - 1 {
 3287                    text.push('\n');
 3288                }
 3289            }
 3290
 3291            if !text.is_empty() {
 3292                cx.write_to_primary(ClipboardItem::new_string(text));
 3293            }
 3294        }
 3295
 3296        let selection_anchors = self.selections.disjoint_anchors_arc();
 3297
 3298        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3299            self.buffer.update(cx, |buffer, cx| {
 3300                buffer.set_active_selections(
 3301                    &selection_anchors,
 3302                    self.selections.line_mode(),
 3303                    self.cursor_shape,
 3304                    cx,
 3305                )
 3306            });
 3307        }
 3308        let display_map = self
 3309            .display_map
 3310            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3311        let buffer = display_map.buffer_snapshot();
 3312        if self.selections.count() == 1 {
 3313            self.add_selections_state = None;
 3314        }
 3315        self.select_next_state = None;
 3316        self.select_prev_state = None;
 3317        self.select_syntax_node_history.try_clear();
 3318        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3319        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3320        self.take_rename(false, window, cx);
 3321
 3322        let newest_selection = self.selections.newest_anchor();
 3323        let new_cursor_position = newest_selection.head();
 3324        let selection_start = newest_selection.start;
 3325
 3326        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3327            self.push_to_nav_history(
 3328                *old_cursor_position,
 3329                Some(new_cursor_position.to_point(buffer)),
 3330                false,
 3331                effects.nav_history == Some(true),
 3332                cx,
 3333            );
 3334        }
 3335
 3336        if local {
 3337            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3338                self.register_buffer(buffer_id, cx);
 3339            }
 3340
 3341            let mut context_menu = self.context_menu.borrow_mut();
 3342            let completion_menu = match context_menu.as_ref() {
 3343                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3344                Some(CodeContextMenu::CodeActions(_)) => {
 3345                    *context_menu = None;
 3346                    None
 3347                }
 3348                None => None,
 3349            };
 3350            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3351            drop(context_menu);
 3352
 3353            if effects.completions
 3354                && let Some(completion_position) = completion_position
 3355            {
 3356                let start_offset = selection_start.to_offset(buffer);
 3357                let position_matches = start_offset == completion_position.to_offset(buffer);
 3358                let continue_showing = if position_matches {
 3359                    if self.snippet_stack.is_empty() {
 3360                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3361                            == Some(CharKind::Word)
 3362                    } else {
 3363                        // Snippet choices can be shown even when the cursor is in whitespace.
 3364                        // Dismissing the menu with actions like backspace is handled by
 3365                        // invalidation regions.
 3366                        true
 3367                    }
 3368                } else {
 3369                    false
 3370                };
 3371
 3372                if continue_showing {
 3373                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3374                } else {
 3375                    self.hide_context_menu(window, cx);
 3376                }
 3377            }
 3378
 3379            hide_hover(self, cx);
 3380
 3381            if old_cursor_position.to_display_point(&display_map).row()
 3382                != new_cursor_position.to_display_point(&display_map).row()
 3383            {
 3384                self.available_code_actions.take();
 3385            }
 3386            self.refresh_code_actions(window, cx);
 3387            self.refresh_document_highlights(cx);
 3388            refresh_linked_ranges(self, window, cx);
 3389
 3390            self.refresh_selected_text_highlights(false, window, cx);
 3391            self.refresh_matching_bracket_highlights(window, cx);
 3392            self.update_visible_edit_prediction(window, cx);
 3393            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3394            self.inline_blame_popover.take();
 3395            if self.git_blame_inline_enabled {
 3396                self.start_inline_blame_timer(window, cx);
 3397            }
 3398        }
 3399
 3400        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3401        cx.emit(EditorEvent::SelectionsChanged { local });
 3402
 3403        let selections = &self.selections.disjoint_anchors_arc();
 3404        if selections.len() == 1 {
 3405            cx.emit(SearchEvent::ActiveMatchChanged)
 3406        }
 3407        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3408            let inmemory_selections = selections
 3409                .iter()
 3410                .map(|s| {
 3411                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3412                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3413                })
 3414                .collect();
 3415            self.update_restoration_data(cx, |data| {
 3416                data.selections = inmemory_selections;
 3417            });
 3418
 3419            if WorkspaceSettings::get(None, cx).restore_on_startup
 3420                != RestoreOnStartupBehavior::EmptyTab
 3421                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3422            {
 3423                let snapshot = self.buffer().read(cx).snapshot(cx);
 3424                let selections = selections.clone();
 3425                let background_executor = cx.background_executor().clone();
 3426                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3427                self.serialize_selections = cx.background_spawn(async move {
 3428                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3429                    let db_selections = selections
 3430                        .iter()
 3431                        .map(|selection| {
 3432                            (
 3433                                selection.start.to_offset(&snapshot).0,
 3434                                selection.end.to_offset(&snapshot).0,
 3435                            )
 3436                        })
 3437                        .collect();
 3438
 3439                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3440                        .await
 3441                        .with_context(|| {
 3442                            format!(
 3443                                "persisting editor selections for editor {editor_id}, \
 3444                                workspace {workspace_id:?}"
 3445                            )
 3446                        })
 3447                        .log_err();
 3448                });
 3449            }
 3450        }
 3451
 3452        cx.notify();
 3453    }
 3454
 3455    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3456        use text::ToOffset as _;
 3457        use text::ToPoint as _;
 3458
 3459        if self.mode.is_minimap()
 3460            || WorkspaceSettings::get(None, cx).restore_on_startup
 3461                == RestoreOnStartupBehavior::EmptyTab
 3462        {
 3463            return;
 3464        }
 3465
 3466        if !self.buffer().read(cx).is_singleton() {
 3467            return;
 3468        }
 3469
 3470        let display_snapshot = self
 3471            .display_map
 3472            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3473        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3474            return;
 3475        };
 3476        let inmemory_folds = display_snapshot
 3477            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3478            .map(|fold| {
 3479                fold.range.start.text_anchor.to_point(&snapshot)
 3480                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3481            })
 3482            .collect();
 3483        self.update_restoration_data(cx, |data| {
 3484            data.folds = inmemory_folds;
 3485        });
 3486
 3487        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3488            return;
 3489        };
 3490        let background_executor = cx.background_executor().clone();
 3491        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3492        let db_folds = display_snapshot
 3493            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3494            .map(|fold| {
 3495                (
 3496                    fold.range.start.text_anchor.to_offset(&snapshot),
 3497                    fold.range.end.text_anchor.to_offset(&snapshot),
 3498                )
 3499            })
 3500            .collect();
 3501        self.serialize_folds = cx.background_spawn(async move {
 3502            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3503            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3504                .await
 3505                .with_context(|| {
 3506                    format!(
 3507                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3508                    )
 3509                })
 3510                .log_err();
 3511        });
 3512    }
 3513
 3514    pub fn sync_selections(
 3515        &mut self,
 3516        other: Entity<Editor>,
 3517        cx: &mut Context<Self>,
 3518    ) -> gpui::Subscription {
 3519        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3520        if !other_selections.is_empty() {
 3521            self.selections
 3522                .change_with(&self.display_snapshot(cx), |selections| {
 3523                    selections.select_anchors(other_selections);
 3524                });
 3525        }
 3526
 3527        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3528            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3529                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3530                if other_selections.is_empty() {
 3531                    return;
 3532                }
 3533                let snapshot = this.display_snapshot(cx);
 3534                this.selections.change_with(&snapshot, |selections| {
 3535                    selections.select_anchors(other_selections);
 3536                });
 3537            }
 3538        });
 3539
 3540        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3541            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3542                let these_selections = this.selections.disjoint_anchors().to_vec();
 3543                if these_selections.is_empty() {
 3544                    return;
 3545                }
 3546                other.update(cx, |other_editor, cx| {
 3547                    let snapshot = other_editor.display_snapshot(cx);
 3548                    other_editor
 3549                        .selections
 3550                        .change_with(&snapshot, |selections| {
 3551                            selections.select_anchors(these_selections);
 3552                        })
 3553                });
 3554            }
 3555        });
 3556
 3557        Subscription::join(other_subscription, this_subscription)
 3558    }
 3559
 3560    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3561        if self.buffer().read(cx).is_singleton() {
 3562            return;
 3563        }
 3564        let snapshot = self.buffer.read(cx).snapshot(cx);
 3565        let buffer_ids: HashSet<BufferId> = self
 3566            .selections
 3567            .disjoint_anchor_ranges()
 3568            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3569            .collect();
 3570        for buffer_id in buffer_ids {
 3571            self.unfold_buffer(buffer_id, cx);
 3572        }
 3573    }
 3574
 3575    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3576    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3577    /// effects of selection change occur at the end of the transaction.
 3578    pub fn change_selections<R>(
 3579        &mut self,
 3580        effects: SelectionEffects,
 3581        window: &mut Window,
 3582        cx: &mut Context<Self>,
 3583        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3584    ) -> R {
 3585        let snapshot = self.display_snapshot(cx);
 3586        if let Some(state) = &mut self.deferred_selection_effects_state {
 3587            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3588            state.effects.completions = effects.completions;
 3589            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3590            let (changed, result) = self.selections.change_with(&snapshot, change);
 3591            state.changed |= changed;
 3592            return result;
 3593        }
 3594        let mut state = DeferredSelectionEffectsState {
 3595            changed: false,
 3596            effects,
 3597            old_cursor_position: self.selections.newest_anchor().head(),
 3598            history_entry: SelectionHistoryEntry {
 3599                selections: self.selections.disjoint_anchors_arc(),
 3600                select_next_state: self.select_next_state.clone(),
 3601                select_prev_state: self.select_prev_state.clone(),
 3602                add_selections_state: self.add_selections_state.clone(),
 3603            },
 3604        };
 3605        let (changed, result) = self.selections.change_with(&snapshot, change);
 3606        state.changed = state.changed || changed;
 3607        if self.defer_selection_effects {
 3608            self.deferred_selection_effects_state = Some(state);
 3609        } else {
 3610            self.apply_selection_effects(state, window, cx);
 3611        }
 3612        result
 3613    }
 3614
 3615    /// Defers the effects of selection change, so that the effects of multiple calls to
 3616    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3617    /// to selection history and the state of popovers based on selection position aren't
 3618    /// erroneously updated.
 3619    pub fn with_selection_effects_deferred<R>(
 3620        &mut self,
 3621        window: &mut Window,
 3622        cx: &mut Context<Self>,
 3623        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3624    ) -> R {
 3625        let already_deferred = self.defer_selection_effects;
 3626        self.defer_selection_effects = true;
 3627        let result = update(self, window, cx);
 3628        if !already_deferred {
 3629            self.defer_selection_effects = false;
 3630            if let Some(state) = self.deferred_selection_effects_state.take() {
 3631                self.apply_selection_effects(state, window, cx);
 3632            }
 3633        }
 3634        result
 3635    }
 3636
 3637    fn apply_selection_effects(
 3638        &mut self,
 3639        state: DeferredSelectionEffectsState,
 3640        window: &mut Window,
 3641        cx: &mut Context<Self>,
 3642    ) {
 3643        if state.changed {
 3644            self.selection_history.push(state.history_entry);
 3645
 3646            if let Some(autoscroll) = state.effects.scroll {
 3647                self.request_autoscroll(autoscroll, cx);
 3648            }
 3649
 3650            let old_cursor_position = &state.old_cursor_position;
 3651
 3652            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3653
 3654            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3655                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3656            }
 3657        }
 3658    }
 3659
 3660    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3661    where
 3662        I: IntoIterator<Item = (Range<S>, T)>,
 3663        S: ToOffset,
 3664        T: Into<Arc<str>>,
 3665    {
 3666        if self.read_only(cx) {
 3667            return;
 3668        }
 3669
 3670        self.buffer
 3671            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3672    }
 3673
 3674    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3675    where
 3676        I: IntoIterator<Item = (Range<S>, T)>,
 3677        S: ToOffset,
 3678        T: Into<Arc<str>>,
 3679    {
 3680        if self.read_only(cx) {
 3681            return;
 3682        }
 3683
 3684        self.buffer.update(cx, |buffer, cx| {
 3685            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3686        });
 3687    }
 3688
 3689    pub fn edit_with_block_indent<I, S, T>(
 3690        &mut self,
 3691        edits: I,
 3692        original_indent_columns: Vec<Option<u32>>,
 3693        cx: &mut Context<Self>,
 3694    ) where
 3695        I: IntoIterator<Item = (Range<S>, T)>,
 3696        S: ToOffset,
 3697        T: Into<Arc<str>>,
 3698    {
 3699        if self.read_only(cx) {
 3700            return;
 3701        }
 3702
 3703        self.buffer.update(cx, |buffer, cx| {
 3704            buffer.edit(
 3705                edits,
 3706                Some(AutoindentMode::Block {
 3707                    original_indent_columns,
 3708                }),
 3709                cx,
 3710            )
 3711        });
 3712    }
 3713
 3714    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3715        self.hide_context_menu(window, cx);
 3716
 3717        match phase {
 3718            SelectPhase::Begin {
 3719                position,
 3720                add,
 3721                click_count,
 3722            } => self.begin_selection(position, add, click_count, window, cx),
 3723            SelectPhase::BeginColumnar {
 3724                position,
 3725                goal_column,
 3726                reset,
 3727                mode,
 3728            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3729            SelectPhase::Extend {
 3730                position,
 3731                click_count,
 3732            } => self.extend_selection(position, click_count, window, cx),
 3733            SelectPhase::Update {
 3734                position,
 3735                goal_column,
 3736                scroll_delta,
 3737            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3738            SelectPhase::End => self.end_selection(window, cx),
 3739        }
 3740    }
 3741
 3742    fn extend_selection(
 3743        &mut self,
 3744        position: DisplayPoint,
 3745        click_count: usize,
 3746        window: &mut Window,
 3747        cx: &mut Context<Self>,
 3748    ) {
 3749        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3750        let tail = self
 3751            .selections
 3752            .newest::<MultiBufferOffset>(&display_map)
 3753            .tail();
 3754        let click_count = click_count.max(match self.selections.select_mode() {
 3755            SelectMode::Character => 1,
 3756            SelectMode::Word(_) => 2,
 3757            SelectMode::Line(_) => 3,
 3758            SelectMode::All => 4,
 3759        });
 3760        self.begin_selection(position, false, click_count, window, cx);
 3761
 3762        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3763
 3764        let current_selection = match self.selections.select_mode() {
 3765            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3766            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3767        };
 3768
 3769        let mut pending_selection = self
 3770            .selections
 3771            .pending_anchor()
 3772            .cloned()
 3773            .expect("extend_selection not called with pending selection");
 3774
 3775        if pending_selection
 3776            .start
 3777            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3778            == Ordering::Greater
 3779        {
 3780            pending_selection.start = current_selection.start;
 3781        }
 3782        if pending_selection
 3783            .end
 3784            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3785            == Ordering::Less
 3786        {
 3787            pending_selection.end = current_selection.end;
 3788            pending_selection.reversed = true;
 3789        }
 3790
 3791        let mut pending_mode = self.selections.pending_mode().unwrap();
 3792        match &mut pending_mode {
 3793            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3794            _ => {}
 3795        }
 3796
 3797        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3798            SelectionEffects::scroll(Autoscroll::fit())
 3799        } else {
 3800            SelectionEffects::no_scroll()
 3801        };
 3802
 3803        self.change_selections(effects, window, cx, |s| {
 3804            s.set_pending(pending_selection.clone(), pending_mode);
 3805            s.set_is_extending(true);
 3806        });
 3807    }
 3808
 3809    fn begin_selection(
 3810        &mut self,
 3811        position: DisplayPoint,
 3812        add: bool,
 3813        click_count: usize,
 3814        window: &mut Window,
 3815        cx: &mut Context<Self>,
 3816    ) {
 3817        if !self.focus_handle.is_focused(window) {
 3818            self.last_focused_descendant = None;
 3819            window.focus(&self.focus_handle);
 3820        }
 3821
 3822        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3823        let buffer = display_map.buffer_snapshot();
 3824        let position = display_map.clip_point(position, Bias::Left);
 3825
 3826        let start;
 3827        let end;
 3828        let mode;
 3829        let mut auto_scroll;
 3830        match click_count {
 3831            1 => {
 3832                start = buffer.anchor_before(position.to_point(&display_map));
 3833                end = start;
 3834                mode = SelectMode::Character;
 3835                auto_scroll = true;
 3836            }
 3837            2 => {
 3838                let position = display_map
 3839                    .clip_point(position, Bias::Left)
 3840                    .to_offset(&display_map, Bias::Left);
 3841                let (range, _) = buffer.surrounding_word(position, None);
 3842                start = buffer.anchor_before(range.start);
 3843                end = buffer.anchor_before(range.end);
 3844                mode = SelectMode::Word(start..end);
 3845                auto_scroll = true;
 3846            }
 3847            3 => {
 3848                let position = display_map
 3849                    .clip_point(position, Bias::Left)
 3850                    .to_point(&display_map);
 3851                let line_start = display_map.prev_line_boundary(position).0;
 3852                let next_line_start = buffer.clip_point(
 3853                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3854                    Bias::Left,
 3855                );
 3856                start = buffer.anchor_before(line_start);
 3857                end = buffer.anchor_before(next_line_start);
 3858                mode = SelectMode::Line(start..end);
 3859                auto_scroll = true;
 3860            }
 3861            _ => {
 3862                start = buffer.anchor_before(MultiBufferOffset(0));
 3863                end = buffer.anchor_before(buffer.len());
 3864                mode = SelectMode::All;
 3865                auto_scroll = false;
 3866            }
 3867        }
 3868        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3869
 3870        let point_to_delete: Option<usize> = {
 3871            let selected_points: Vec<Selection<Point>> =
 3872                self.selections.disjoint_in_range(start..end, &display_map);
 3873
 3874            if !add || click_count > 1 {
 3875                None
 3876            } else if !selected_points.is_empty() {
 3877                Some(selected_points[0].id)
 3878            } else {
 3879                let clicked_point_already_selected =
 3880                    self.selections.disjoint_anchors().iter().find(|selection| {
 3881                        selection.start.to_point(buffer) == start.to_point(buffer)
 3882                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3883                    });
 3884
 3885                clicked_point_already_selected.map(|selection| selection.id)
 3886            }
 3887        };
 3888
 3889        let selections_count = self.selections.count();
 3890        let effects = if auto_scroll {
 3891            SelectionEffects::default()
 3892        } else {
 3893            SelectionEffects::no_scroll()
 3894        };
 3895
 3896        self.change_selections(effects, window, cx, |s| {
 3897            if let Some(point_to_delete) = point_to_delete {
 3898                s.delete(point_to_delete);
 3899
 3900                if selections_count == 1 {
 3901                    s.set_pending_anchor_range(start..end, mode);
 3902                }
 3903            } else {
 3904                if !add {
 3905                    s.clear_disjoint();
 3906                }
 3907
 3908                s.set_pending_anchor_range(start..end, mode);
 3909            }
 3910        });
 3911    }
 3912
 3913    fn begin_columnar_selection(
 3914        &mut self,
 3915        position: DisplayPoint,
 3916        goal_column: u32,
 3917        reset: bool,
 3918        mode: ColumnarMode,
 3919        window: &mut Window,
 3920        cx: &mut Context<Self>,
 3921    ) {
 3922        if !self.focus_handle.is_focused(window) {
 3923            self.last_focused_descendant = None;
 3924            window.focus(&self.focus_handle);
 3925        }
 3926
 3927        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3928
 3929        if reset {
 3930            let pointer_position = display_map
 3931                .buffer_snapshot()
 3932                .anchor_before(position.to_point(&display_map));
 3933
 3934            self.change_selections(
 3935                SelectionEffects::scroll(Autoscroll::newest()),
 3936                window,
 3937                cx,
 3938                |s| {
 3939                    s.clear_disjoint();
 3940                    s.set_pending_anchor_range(
 3941                        pointer_position..pointer_position,
 3942                        SelectMode::Character,
 3943                    );
 3944                },
 3945            );
 3946        };
 3947
 3948        let tail = self.selections.newest::<Point>(&display_map).tail();
 3949        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3950        self.columnar_selection_state = match mode {
 3951            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3952                selection_tail: selection_anchor,
 3953                display_point: if reset {
 3954                    if position.column() != goal_column {
 3955                        Some(DisplayPoint::new(position.row(), goal_column))
 3956                    } else {
 3957                        None
 3958                    }
 3959                } else {
 3960                    None
 3961                },
 3962            }),
 3963            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3964                selection_tail: selection_anchor,
 3965            }),
 3966        };
 3967
 3968        if !reset {
 3969            self.select_columns(position, goal_column, &display_map, window, cx);
 3970        }
 3971    }
 3972
 3973    fn update_selection(
 3974        &mut self,
 3975        position: DisplayPoint,
 3976        goal_column: u32,
 3977        scroll_delta: gpui::Point<f32>,
 3978        window: &mut Window,
 3979        cx: &mut Context<Self>,
 3980    ) {
 3981        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3982
 3983        if self.columnar_selection_state.is_some() {
 3984            self.select_columns(position, goal_column, &display_map, window, cx);
 3985        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3986            let buffer = display_map.buffer_snapshot();
 3987            let head;
 3988            let tail;
 3989            let mode = self.selections.pending_mode().unwrap();
 3990            match &mode {
 3991                SelectMode::Character => {
 3992                    head = position.to_point(&display_map);
 3993                    tail = pending.tail().to_point(buffer);
 3994                }
 3995                SelectMode::Word(original_range) => {
 3996                    let offset = display_map
 3997                        .clip_point(position, Bias::Left)
 3998                        .to_offset(&display_map, Bias::Left);
 3999                    let original_range = original_range.to_offset(buffer);
 4000
 4001                    let head_offset = if buffer.is_inside_word(offset, None)
 4002                        || original_range.contains(&offset)
 4003                    {
 4004                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4005                        if word_range.start < original_range.start {
 4006                            word_range.start
 4007                        } else {
 4008                            word_range.end
 4009                        }
 4010                    } else {
 4011                        offset
 4012                    };
 4013
 4014                    head = head_offset.to_point(buffer);
 4015                    if head_offset <= original_range.start {
 4016                        tail = original_range.end.to_point(buffer);
 4017                    } else {
 4018                        tail = original_range.start.to_point(buffer);
 4019                    }
 4020                }
 4021                SelectMode::Line(original_range) => {
 4022                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4023
 4024                    let position = display_map
 4025                        .clip_point(position, Bias::Left)
 4026                        .to_point(&display_map);
 4027                    let line_start = display_map.prev_line_boundary(position).0;
 4028                    let next_line_start = buffer.clip_point(
 4029                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4030                        Bias::Left,
 4031                    );
 4032
 4033                    if line_start < original_range.start {
 4034                        head = line_start
 4035                    } else {
 4036                        head = next_line_start
 4037                    }
 4038
 4039                    if head <= original_range.start {
 4040                        tail = original_range.end;
 4041                    } else {
 4042                        tail = original_range.start;
 4043                    }
 4044                }
 4045                SelectMode::All => {
 4046                    return;
 4047                }
 4048            };
 4049
 4050            if head < tail {
 4051                pending.start = buffer.anchor_before(head);
 4052                pending.end = buffer.anchor_before(tail);
 4053                pending.reversed = true;
 4054            } else {
 4055                pending.start = buffer.anchor_before(tail);
 4056                pending.end = buffer.anchor_before(head);
 4057                pending.reversed = false;
 4058            }
 4059
 4060            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4061                s.set_pending(pending.clone(), mode);
 4062            });
 4063        } else {
 4064            log::error!("update_selection dispatched with no pending selection");
 4065            return;
 4066        }
 4067
 4068        self.apply_scroll_delta(scroll_delta, window, cx);
 4069        cx.notify();
 4070    }
 4071
 4072    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4073        self.columnar_selection_state.take();
 4074        if let Some(pending_mode) = self.selections.pending_mode() {
 4075            let selections = self
 4076                .selections
 4077                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4078            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4079                s.select(selections);
 4080                s.clear_pending();
 4081                if s.is_extending() {
 4082                    s.set_is_extending(false);
 4083                } else {
 4084                    s.set_select_mode(pending_mode);
 4085                }
 4086            });
 4087        }
 4088    }
 4089
 4090    fn select_columns(
 4091        &mut self,
 4092        head: DisplayPoint,
 4093        goal_column: u32,
 4094        display_map: &DisplaySnapshot,
 4095        window: &mut Window,
 4096        cx: &mut Context<Self>,
 4097    ) {
 4098        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4099            return;
 4100        };
 4101
 4102        let tail = match columnar_state {
 4103            ColumnarSelectionState::FromMouse {
 4104                selection_tail,
 4105                display_point,
 4106            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4107            ColumnarSelectionState::FromSelection { selection_tail } => {
 4108                selection_tail.to_display_point(display_map)
 4109            }
 4110        };
 4111
 4112        let start_row = cmp::min(tail.row(), head.row());
 4113        let end_row = cmp::max(tail.row(), head.row());
 4114        let start_column = cmp::min(tail.column(), goal_column);
 4115        let end_column = cmp::max(tail.column(), goal_column);
 4116        let reversed = start_column < tail.column();
 4117
 4118        let selection_ranges = (start_row.0..=end_row.0)
 4119            .map(DisplayRow)
 4120            .filter_map(|row| {
 4121                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4122                    || start_column <= display_map.line_len(row))
 4123                    && !display_map.is_block_line(row)
 4124                {
 4125                    let start = display_map
 4126                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4127                        .to_point(display_map);
 4128                    let end = display_map
 4129                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4130                        .to_point(display_map);
 4131                    if reversed {
 4132                        Some(end..start)
 4133                    } else {
 4134                        Some(start..end)
 4135                    }
 4136                } else {
 4137                    None
 4138                }
 4139            })
 4140            .collect::<Vec<_>>();
 4141        if selection_ranges.is_empty() {
 4142            return;
 4143        }
 4144
 4145        let ranges = match columnar_state {
 4146            ColumnarSelectionState::FromMouse { .. } => {
 4147                let mut non_empty_ranges = selection_ranges
 4148                    .iter()
 4149                    .filter(|selection_range| selection_range.start != selection_range.end)
 4150                    .peekable();
 4151                if non_empty_ranges.peek().is_some() {
 4152                    non_empty_ranges.cloned().collect()
 4153                } else {
 4154                    selection_ranges
 4155                }
 4156            }
 4157            _ => selection_ranges,
 4158        };
 4159
 4160        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4161            s.select_ranges(ranges);
 4162        });
 4163        cx.notify();
 4164    }
 4165
 4166    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4167        self.selections
 4168            .all_adjusted(snapshot)
 4169            .iter()
 4170            .any(|selection| !selection.is_empty())
 4171    }
 4172
 4173    pub fn has_pending_nonempty_selection(&self) -> bool {
 4174        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4175            Some(Selection { start, end, .. }) => start != end,
 4176            None => false,
 4177        };
 4178
 4179        pending_nonempty_selection
 4180            || (self.columnar_selection_state.is_some()
 4181                && self.selections.disjoint_anchors().len() > 1)
 4182    }
 4183
 4184    pub fn has_pending_selection(&self) -> bool {
 4185        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4186    }
 4187
 4188    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4189        self.selection_mark_mode = false;
 4190        self.selection_drag_state = SelectionDragState::None;
 4191
 4192        if self.dismiss_menus_and_popups(true, window, cx) {
 4193            cx.notify();
 4194            return;
 4195        }
 4196        if self.clear_expanded_diff_hunks(cx) {
 4197            cx.notify();
 4198            return;
 4199        }
 4200        if self.show_git_blame_gutter {
 4201            self.show_git_blame_gutter = false;
 4202            cx.notify();
 4203            return;
 4204        }
 4205
 4206        if self.mode.is_full()
 4207            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4208        {
 4209            cx.notify();
 4210            return;
 4211        }
 4212
 4213        cx.propagate();
 4214    }
 4215
 4216    pub fn dismiss_menus_and_popups(
 4217        &mut self,
 4218        is_user_requested: bool,
 4219        window: &mut Window,
 4220        cx: &mut Context<Self>,
 4221    ) -> bool {
 4222        let mut dismissed = false;
 4223
 4224        dismissed |= self.take_rename(false, window, cx).is_some();
 4225        dismissed |= self.hide_blame_popover(true, cx);
 4226        dismissed |= hide_hover(self, cx);
 4227        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4228        dismissed |= self.hide_context_menu(window, cx).is_some();
 4229        dismissed |= self.mouse_context_menu.take().is_some();
 4230        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4231        dismissed |= self.snippet_stack.pop().is_some();
 4232
 4233        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4234            self.dismiss_diagnostics(cx);
 4235            dismissed = true;
 4236        }
 4237
 4238        dismissed
 4239    }
 4240
 4241    fn linked_editing_ranges_for(
 4242        &self,
 4243        selection: Range<text::Anchor>,
 4244        cx: &App,
 4245    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4246        if self.linked_edit_ranges.is_empty() {
 4247            return None;
 4248        }
 4249        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4250            selection.end.buffer_id.and_then(|end_buffer_id| {
 4251                if selection.start.buffer_id != Some(end_buffer_id) {
 4252                    return None;
 4253                }
 4254                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4255                let snapshot = buffer.read(cx).snapshot();
 4256                self.linked_edit_ranges
 4257                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4258                    .map(|ranges| (ranges, snapshot, buffer))
 4259            })?;
 4260        use text::ToOffset as TO;
 4261        // find offset from the start of current range to current cursor position
 4262        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4263
 4264        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4265        let start_difference = start_offset - start_byte_offset;
 4266        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4267        let end_difference = end_offset - start_byte_offset;
 4268        // Current range has associated linked ranges.
 4269        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4270        for range in linked_ranges.iter() {
 4271            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4272            let end_offset = start_offset + end_difference;
 4273            let start_offset = start_offset + start_difference;
 4274            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4275                continue;
 4276            }
 4277            if self.selections.disjoint_anchor_ranges().any(|s| {
 4278                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4279                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4280                {
 4281                    return false;
 4282                }
 4283                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4284                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4285            }) {
 4286                continue;
 4287            }
 4288            let start = buffer_snapshot.anchor_after(start_offset);
 4289            let end = buffer_snapshot.anchor_after(end_offset);
 4290            linked_edits
 4291                .entry(buffer.clone())
 4292                .or_default()
 4293                .push(start..end);
 4294        }
 4295        Some(linked_edits)
 4296    }
 4297
 4298    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4299        let text: Arc<str> = text.into();
 4300
 4301        if self.read_only(cx) {
 4302            return;
 4303        }
 4304
 4305        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4306
 4307        self.unfold_buffers_with_selections(cx);
 4308
 4309        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4310        let mut bracket_inserted = false;
 4311        let mut edits = Vec::new();
 4312        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4313        let mut new_selections = Vec::with_capacity(selections.len());
 4314        let mut new_autoclose_regions = Vec::new();
 4315        let snapshot = self.buffer.read(cx).read(cx);
 4316        let mut clear_linked_edit_ranges = false;
 4317
 4318        for (selection, autoclose_region) in
 4319            self.selections_with_autoclose_regions(selections, &snapshot)
 4320        {
 4321            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4322                // Determine if the inserted text matches the opening or closing
 4323                // bracket of any of this language's bracket pairs.
 4324                let mut bracket_pair = None;
 4325                let mut is_bracket_pair_start = false;
 4326                let mut is_bracket_pair_end = false;
 4327                if !text.is_empty() {
 4328                    let mut bracket_pair_matching_end = None;
 4329                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4330                    //  and they are removing the character that triggered IME popup.
 4331                    for (pair, enabled) in scope.brackets() {
 4332                        if !pair.close && !pair.surround {
 4333                            continue;
 4334                        }
 4335
 4336                        if enabled && pair.start.ends_with(text.as_ref()) {
 4337                            let prefix_len = pair.start.len() - text.len();
 4338                            let preceding_text_matches_prefix = prefix_len == 0
 4339                                || (selection.start.column >= (prefix_len as u32)
 4340                                    && snapshot.contains_str_at(
 4341                                        Point::new(
 4342                                            selection.start.row,
 4343                                            selection.start.column - (prefix_len as u32),
 4344                                        ),
 4345                                        &pair.start[..prefix_len],
 4346                                    ));
 4347                            if preceding_text_matches_prefix {
 4348                                bracket_pair = Some(pair.clone());
 4349                                is_bracket_pair_start = true;
 4350                                break;
 4351                            }
 4352                        }
 4353                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4354                        {
 4355                            // take first bracket pair matching end, but don't break in case a later bracket
 4356                            // pair matches start
 4357                            bracket_pair_matching_end = Some(pair.clone());
 4358                        }
 4359                    }
 4360                    if let Some(end) = bracket_pair_matching_end
 4361                        && bracket_pair.is_none()
 4362                    {
 4363                        bracket_pair = Some(end);
 4364                        is_bracket_pair_end = true;
 4365                    }
 4366                }
 4367
 4368                if let Some(bracket_pair) = bracket_pair {
 4369                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4370                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4371                    let auto_surround =
 4372                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4373                    if selection.is_empty() {
 4374                        if is_bracket_pair_start {
 4375                            // If the inserted text is a suffix of an opening bracket and the
 4376                            // selection is preceded by the rest of the opening bracket, then
 4377                            // insert the closing bracket.
 4378                            let following_text_allows_autoclose = snapshot
 4379                                .chars_at(selection.start)
 4380                                .next()
 4381                                .is_none_or(|c| scope.should_autoclose_before(c));
 4382
 4383                            let preceding_text_allows_autoclose = selection.start.column == 0
 4384                                || snapshot
 4385                                    .reversed_chars_at(selection.start)
 4386                                    .next()
 4387                                    .is_none_or(|c| {
 4388                                        bracket_pair.start != bracket_pair.end
 4389                                            || !snapshot
 4390                                                .char_classifier_at(selection.start)
 4391                                                .is_word(c)
 4392                                    });
 4393
 4394                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4395                                && bracket_pair.start.len() == 1
 4396                            {
 4397                                let target = bracket_pair.start.chars().next().unwrap();
 4398                                let mut byte_offset = 0u32;
 4399                                let current_line_count = snapshot
 4400                                    .reversed_chars_at(selection.start)
 4401                                    .take_while(|&c| c != '\n')
 4402                                    .filter(|c| {
 4403                                        byte_offset += c.len_utf8() as u32;
 4404                                        if *c != target {
 4405                                            return false;
 4406                                        }
 4407
 4408                                        let point = Point::new(
 4409                                            selection.start.row,
 4410                                            selection.start.column.saturating_sub(byte_offset),
 4411                                        );
 4412
 4413                                        let is_enabled = snapshot
 4414                                            .language_scope_at(point)
 4415                                            .and_then(|scope| {
 4416                                                scope
 4417                                                    .brackets()
 4418                                                    .find(|(pair, _)| {
 4419                                                        pair.start == bracket_pair.start
 4420                                                    })
 4421                                                    .map(|(_, enabled)| enabled)
 4422                                            })
 4423                                            .unwrap_or(true);
 4424
 4425                                        let is_delimiter = snapshot
 4426                                            .language_scope_at(Point::new(
 4427                                                point.row,
 4428                                                point.column + 1,
 4429                                            ))
 4430                                            .and_then(|scope| {
 4431                                                scope
 4432                                                    .brackets()
 4433                                                    .find(|(pair, _)| {
 4434                                                        pair.start == bracket_pair.start
 4435                                                    })
 4436                                                    .map(|(_, enabled)| !enabled)
 4437                                            })
 4438                                            .unwrap_or(false);
 4439
 4440                                        is_enabled && !is_delimiter
 4441                                    })
 4442                                    .count();
 4443                                current_line_count % 2 == 1
 4444                            } else {
 4445                                false
 4446                            };
 4447
 4448                            if autoclose
 4449                                && bracket_pair.close
 4450                                && following_text_allows_autoclose
 4451                                && preceding_text_allows_autoclose
 4452                                && !is_closing_quote
 4453                            {
 4454                                let anchor = snapshot.anchor_before(selection.end);
 4455                                new_selections.push((selection.map(|_| anchor), text.len()));
 4456                                new_autoclose_regions.push((
 4457                                    anchor,
 4458                                    text.len(),
 4459                                    selection.id,
 4460                                    bracket_pair.clone(),
 4461                                ));
 4462                                edits.push((
 4463                                    selection.range(),
 4464                                    format!("{}{}", text, bracket_pair.end).into(),
 4465                                ));
 4466                                bracket_inserted = true;
 4467                                continue;
 4468                            }
 4469                        }
 4470
 4471                        if let Some(region) = autoclose_region {
 4472                            // If the selection is followed by an auto-inserted closing bracket,
 4473                            // then don't insert that closing bracket again; just move the selection
 4474                            // past the closing bracket.
 4475                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4476                                && text.as_ref() == region.pair.end.as_str()
 4477                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4478                            if should_skip {
 4479                                let anchor = snapshot.anchor_after(selection.end);
 4480                                new_selections
 4481                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4482                                continue;
 4483                            }
 4484                        }
 4485
 4486                        let always_treat_brackets_as_autoclosed = snapshot
 4487                            .language_settings_at(selection.start, cx)
 4488                            .always_treat_brackets_as_autoclosed;
 4489                        if always_treat_brackets_as_autoclosed
 4490                            && is_bracket_pair_end
 4491                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4492                        {
 4493                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4494                            // and the inserted text is a closing bracket and the selection is followed
 4495                            // by the closing bracket then move the selection past the closing bracket.
 4496                            let anchor = snapshot.anchor_after(selection.end);
 4497                            new_selections.push((selection.map(|_| anchor), text.len()));
 4498                            continue;
 4499                        }
 4500                    }
 4501                    // If an opening bracket is 1 character long and is typed while
 4502                    // text is selected, then surround that text with the bracket pair.
 4503                    else if auto_surround
 4504                        && bracket_pair.surround
 4505                        && is_bracket_pair_start
 4506                        && bracket_pair.start.chars().count() == 1
 4507                    {
 4508                        edits.push((selection.start..selection.start, text.clone()));
 4509                        edits.push((
 4510                            selection.end..selection.end,
 4511                            bracket_pair.end.as_str().into(),
 4512                        ));
 4513                        bracket_inserted = true;
 4514                        new_selections.push((
 4515                            Selection {
 4516                                id: selection.id,
 4517                                start: snapshot.anchor_after(selection.start),
 4518                                end: snapshot.anchor_before(selection.end),
 4519                                reversed: selection.reversed,
 4520                                goal: selection.goal,
 4521                            },
 4522                            0,
 4523                        ));
 4524                        continue;
 4525                    }
 4526                }
 4527            }
 4528
 4529            if self.auto_replace_emoji_shortcode
 4530                && selection.is_empty()
 4531                && text.as_ref().ends_with(':')
 4532                && let Some(possible_emoji_short_code) =
 4533                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4534                && !possible_emoji_short_code.is_empty()
 4535                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4536            {
 4537                let emoji_shortcode_start = Point::new(
 4538                    selection.start.row,
 4539                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4540                );
 4541
 4542                // Remove shortcode from buffer
 4543                edits.push((
 4544                    emoji_shortcode_start..selection.start,
 4545                    "".to_string().into(),
 4546                ));
 4547                new_selections.push((
 4548                    Selection {
 4549                        id: selection.id,
 4550                        start: snapshot.anchor_after(emoji_shortcode_start),
 4551                        end: snapshot.anchor_before(selection.start),
 4552                        reversed: selection.reversed,
 4553                        goal: selection.goal,
 4554                    },
 4555                    0,
 4556                ));
 4557
 4558                // Insert emoji
 4559                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4560                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4561                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4562
 4563                continue;
 4564            }
 4565
 4566            // If not handling any auto-close operation, then just replace the selected
 4567            // text with the given input and move the selection to the end of the
 4568            // newly inserted text.
 4569            let anchor = snapshot.anchor_after(selection.end);
 4570            if !self.linked_edit_ranges.is_empty() {
 4571                let start_anchor = snapshot.anchor_before(selection.start);
 4572
 4573                let is_word_char = text.chars().next().is_none_or(|char| {
 4574                    let classifier = snapshot
 4575                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4576                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4577                    classifier.is_word(char)
 4578                });
 4579
 4580                if is_word_char {
 4581                    if let Some(ranges) = self
 4582                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4583                    {
 4584                        for (buffer, edits) in ranges {
 4585                            linked_edits
 4586                                .entry(buffer.clone())
 4587                                .or_default()
 4588                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4589                        }
 4590                    }
 4591                } else {
 4592                    clear_linked_edit_ranges = true;
 4593                }
 4594            }
 4595
 4596            new_selections.push((selection.map(|_| anchor), 0));
 4597            edits.push((selection.start..selection.end, text.clone()));
 4598        }
 4599
 4600        drop(snapshot);
 4601
 4602        self.transact(window, cx, |this, window, cx| {
 4603            if clear_linked_edit_ranges {
 4604                this.linked_edit_ranges.clear();
 4605            }
 4606            let initial_buffer_versions =
 4607                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4608
 4609            this.buffer.update(cx, |buffer, cx| {
 4610                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4611            });
 4612            for (buffer, edits) in linked_edits {
 4613                buffer.update(cx, |buffer, cx| {
 4614                    let snapshot = buffer.snapshot();
 4615                    let edits = edits
 4616                        .into_iter()
 4617                        .map(|(range, text)| {
 4618                            use text::ToPoint as TP;
 4619                            let end_point = TP::to_point(&range.end, &snapshot);
 4620                            let start_point = TP::to_point(&range.start, &snapshot);
 4621                            (start_point..end_point, text)
 4622                        })
 4623                        .sorted_by_key(|(range, _)| range.start);
 4624                    buffer.edit(edits, None, cx);
 4625                })
 4626            }
 4627            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4628            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4629            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4630            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4631                new_anchor_selections,
 4632                &map,
 4633            )
 4634            .zip(new_selection_deltas)
 4635            .map(|(selection, delta)| Selection {
 4636                id: selection.id,
 4637                start: selection.start + delta,
 4638                end: selection.end + delta,
 4639                reversed: selection.reversed,
 4640                goal: SelectionGoal::None,
 4641            })
 4642            .collect::<Vec<_>>();
 4643
 4644            let mut i = 0;
 4645            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4646                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4647                let start = map.buffer_snapshot().anchor_before(position);
 4648                let end = map.buffer_snapshot().anchor_after(position);
 4649                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4650                    match existing_state
 4651                        .range
 4652                        .start
 4653                        .cmp(&start, map.buffer_snapshot())
 4654                    {
 4655                        Ordering::Less => i += 1,
 4656                        Ordering::Greater => break,
 4657                        Ordering::Equal => {
 4658                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4659                                Ordering::Less => i += 1,
 4660                                Ordering::Equal => break,
 4661                                Ordering::Greater => break,
 4662                            }
 4663                        }
 4664                    }
 4665                }
 4666                this.autoclose_regions.insert(
 4667                    i,
 4668                    AutocloseRegion {
 4669                        selection_id,
 4670                        range: start..end,
 4671                        pair,
 4672                    },
 4673                );
 4674            }
 4675
 4676            let had_active_edit_prediction = this.has_active_edit_prediction();
 4677            this.change_selections(
 4678                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4679                window,
 4680                cx,
 4681                |s| s.select(new_selections),
 4682            );
 4683
 4684            if !bracket_inserted
 4685                && let Some(on_type_format_task) =
 4686                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4687            {
 4688                on_type_format_task.detach_and_log_err(cx);
 4689            }
 4690
 4691            let editor_settings = EditorSettings::get_global(cx);
 4692            if bracket_inserted
 4693                && (editor_settings.auto_signature_help
 4694                    || editor_settings.show_signature_help_after_edits)
 4695            {
 4696                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4697            }
 4698
 4699            let trigger_in_words =
 4700                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4701            if this.hard_wrap.is_some() {
 4702                let latest: Range<Point> = this.selections.newest(&map).range();
 4703                if latest.is_empty()
 4704                    && this
 4705                        .buffer()
 4706                        .read(cx)
 4707                        .snapshot(cx)
 4708                        .line_len(MultiBufferRow(latest.start.row))
 4709                        == latest.start.column
 4710                {
 4711                    this.rewrap_impl(
 4712                        RewrapOptions {
 4713                            override_language_settings: true,
 4714                            preserve_existing_whitespace: true,
 4715                        },
 4716                        cx,
 4717                    )
 4718                }
 4719            }
 4720            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4721            refresh_linked_ranges(this, window, cx);
 4722            this.refresh_edit_prediction(true, false, window, cx);
 4723            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4724        });
 4725    }
 4726
 4727    fn find_possible_emoji_shortcode_at_position(
 4728        snapshot: &MultiBufferSnapshot,
 4729        position: Point,
 4730    ) -> Option<String> {
 4731        let mut chars = Vec::new();
 4732        let mut found_colon = false;
 4733        for char in snapshot.reversed_chars_at(position).take(100) {
 4734            // Found a possible emoji shortcode in the middle of the buffer
 4735            if found_colon {
 4736                if char.is_whitespace() {
 4737                    chars.reverse();
 4738                    return Some(chars.iter().collect());
 4739                }
 4740                // If the previous character is not a whitespace, we are in the middle of a word
 4741                // and we only want to complete the shortcode if the word is made up of other emojis
 4742                let mut containing_word = String::new();
 4743                for ch in snapshot
 4744                    .reversed_chars_at(position)
 4745                    .skip(chars.len() + 1)
 4746                    .take(100)
 4747                {
 4748                    if ch.is_whitespace() {
 4749                        break;
 4750                    }
 4751                    containing_word.push(ch);
 4752                }
 4753                let containing_word = containing_word.chars().rev().collect::<String>();
 4754                if util::word_consists_of_emojis(containing_word.as_str()) {
 4755                    chars.reverse();
 4756                    return Some(chars.iter().collect());
 4757                }
 4758            }
 4759
 4760            if char.is_whitespace() || !char.is_ascii() {
 4761                return None;
 4762            }
 4763            if char == ':' {
 4764                found_colon = true;
 4765            } else {
 4766                chars.push(char);
 4767            }
 4768        }
 4769        // Found a possible emoji shortcode at the beginning of the buffer
 4770        chars.reverse();
 4771        Some(chars.iter().collect())
 4772    }
 4773
 4774    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4775        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4776        self.transact(window, cx, |this, window, cx| {
 4777            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4778                let selections = this
 4779                    .selections
 4780                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4781                let multi_buffer = this.buffer.read(cx);
 4782                let buffer = multi_buffer.snapshot(cx);
 4783                selections
 4784                    .iter()
 4785                    .map(|selection| {
 4786                        let start_point = selection.start.to_point(&buffer);
 4787                        let mut existing_indent =
 4788                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4789                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4790                        let start = selection.start;
 4791                        let end = selection.end;
 4792                        let selection_is_empty = start == end;
 4793                        let language_scope = buffer.language_scope_at(start);
 4794                        let (comment_delimiter, doc_delimiter, newline_formatting) =
 4795                            if let Some(language) = &language_scope {
 4796                                let mut newline_formatting =
 4797                                    NewlineFormatting::new(&buffer, start..end, language);
 4798
 4799                                // Comment extension on newline is allowed only for cursor selections
 4800                                let comment_delimiter = maybe!({
 4801                                    if !selection_is_empty {
 4802                                        return None;
 4803                                    }
 4804
 4805                                    if !multi_buffer.language_settings(cx).extend_comment_on_newline
 4806                                    {
 4807                                        return None;
 4808                                    }
 4809
 4810                                    return comment_delimiter_for_newline(
 4811                                        &start_point,
 4812                                        &buffer,
 4813                                        language,
 4814                                    );
 4815                                });
 4816
 4817                                let doc_delimiter = maybe!({
 4818                                    if !selection_is_empty {
 4819                                        return None;
 4820                                    }
 4821
 4822                                    if !multi_buffer.language_settings(cx).extend_comment_on_newline
 4823                                    {
 4824                                        return None;
 4825                                    }
 4826
 4827                                    return documentation_delimiter_for_newline(
 4828                                        &start_point,
 4829                                        &buffer,
 4830                                        language,
 4831                                        &mut newline_formatting,
 4832                                    );
 4833                                });
 4834
 4835                                (comment_delimiter, doc_delimiter, newline_formatting)
 4836                            } else {
 4837                                (None, None, NewlineFormatting::default())
 4838                            };
 4839
 4840                        let prevent_auto_indent = doc_delimiter.is_some();
 4841                        let delimiter = comment_delimiter.or(doc_delimiter);
 4842
 4843                        let capacity_for_delimiter =
 4844                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4845                        let mut new_text = String::with_capacity(
 4846                            1 + capacity_for_delimiter
 4847                                + existing_indent.len as usize
 4848                                + newline_formatting.indent_on_newline.len as usize
 4849                                + newline_formatting.indent_on_extra_newline.len as usize,
 4850                        );
 4851                        new_text.push('\n');
 4852                        new_text.extend(existing_indent.chars());
 4853                        new_text.extend(newline_formatting.indent_on_newline.chars());
 4854
 4855                        if let Some(delimiter) = &delimiter {
 4856                            new_text.push_str(delimiter);
 4857                        }
 4858
 4859                        if newline_formatting.insert_extra_newline {
 4860                            new_text.push('\n');
 4861                            new_text.extend(existing_indent.chars());
 4862                            new_text.extend(newline_formatting.indent_on_extra_newline.chars());
 4863                        }
 4864
 4865                        let anchor = buffer.anchor_after(end);
 4866                        let new_selection = selection.map(|_| anchor);
 4867                        (
 4868                            ((start..end, new_text), prevent_auto_indent),
 4869                            (newline_formatting.insert_extra_newline, new_selection),
 4870                        )
 4871                    })
 4872                    .unzip()
 4873            };
 4874
 4875            let mut auto_indent_edits = Vec::new();
 4876            let mut edits = Vec::new();
 4877            for (edit, prevent_auto_indent) in edits_with_flags {
 4878                if prevent_auto_indent {
 4879                    edits.push(edit);
 4880                } else {
 4881                    auto_indent_edits.push(edit);
 4882                }
 4883            }
 4884            if !edits.is_empty() {
 4885                this.edit(edits, cx);
 4886            }
 4887            if !auto_indent_edits.is_empty() {
 4888                this.edit_with_autoindent(auto_indent_edits, cx);
 4889            }
 4890
 4891            let buffer = this.buffer.read(cx).snapshot(cx);
 4892            let new_selections = selection_info
 4893                .into_iter()
 4894                .map(|(extra_newline_inserted, new_selection)| {
 4895                    let mut cursor = new_selection.end.to_point(&buffer);
 4896                    if extra_newline_inserted {
 4897                        cursor.row -= 1;
 4898                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4899                    }
 4900                    new_selection.map(|_| cursor)
 4901                })
 4902                .collect();
 4903
 4904            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4905            this.refresh_edit_prediction(true, false, window, cx);
 4906            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 4907                task.detach_and_log_err(cx);
 4908            }
 4909        });
 4910    }
 4911
 4912    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4913        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4914
 4915        let buffer = self.buffer.read(cx);
 4916        let snapshot = buffer.snapshot(cx);
 4917
 4918        let mut edits = Vec::new();
 4919        let mut rows = Vec::new();
 4920
 4921        for (rows_inserted, selection) in self
 4922            .selections
 4923            .all_adjusted(&self.display_snapshot(cx))
 4924            .into_iter()
 4925            .enumerate()
 4926        {
 4927            let cursor = selection.head();
 4928            let row = cursor.row;
 4929
 4930            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4931
 4932            let newline = "\n".to_string();
 4933            edits.push((start_of_line..start_of_line, newline));
 4934
 4935            rows.push(row + rows_inserted as u32);
 4936        }
 4937
 4938        self.transact(window, cx, |editor, window, cx| {
 4939            editor.edit(edits, cx);
 4940
 4941            editor.change_selections(Default::default(), window, cx, |s| {
 4942                let mut index = 0;
 4943                s.move_cursors_with(|map, _, _| {
 4944                    let row = rows[index];
 4945                    index += 1;
 4946
 4947                    let point = Point::new(row, 0);
 4948                    let boundary = map.next_line_boundary(point).1;
 4949                    let clipped = map.clip_point(boundary, Bias::Left);
 4950
 4951                    (clipped, SelectionGoal::None)
 4952                });
 4953            });
 4954
 4955            let mut indent_edits = Vec::new();
 4956            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4957            for row in rows {
 4958                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4959                for (row, indent) in indents {
 4960                    if indent.len == 0 {
 4961                        continue;
 4962                    }
 4963
 4964                    let text = match indent.kind {
 4965                        IndentKind::Space => " ".repeat(indent.len as usize),
 4966                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4967                    };
 4968                    let point = Point::new(row.0, 0);
 4969                    indent_edits.push((point..point, text));
 4970                }
 4971            }
 4972            editor.edit(indent_edits, cx);
 4973            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 4974                format.detach_and_log_err(cx);
 4975            }
 4976        });
 4977    }
 4978
 4979    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4980        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4981
 4982        let buffer = self.buffer.read(cx);
 4983        let snapshot = buffer.snapshot(cx);
 4984
 4985        let mut edits = Vec::new();
 4986        let mut rows = Vec::new();
 4987        let mut rows_inserted = 0;
 4988
 4989        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4990            let cursor = selection.head();
 4991            let row = cursor.row;
 4992
 4993            let point = Point::new(row + 1, 0);
 4994            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4995
 4996            let newline = "\n".to_string();
 4997            edits.push((start_of_line..start_of_line, newline));
 4998
 4999            rows_inserted += 1;
 5000            rows.push(row + rows_inserted);
 5001        }
 5002
 5003        self.transact(window, cx, |editor, window, cx| {
 5004            editor.edit(edits, cx);
 5005
 5006            editor.change_selections(Default::default(), window, cx, |s| {
 5007                let mut index = 0;
 5008                s.move_cursors_with(|map, _, _| {
 5009                    let row = rows[index];
 5010                    index += 1;
 5011
 5012                    let point = Point::new(row, 0);
 5013                    let boundary = map.next_line_boundary(point).1;
 5014                    let clipped = map.clip_point(boundary, Bias::Left);
 5015
 5016                    (clipped, SelectionGoal::None)
 5017                });
 5018            });
 5019
 5020            let mut indent_edits = Vec::new();
 5021            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5022            for row in rows {
 5023                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5024                for (row, indent) in indents {
 5025                    if indent.len == 0 {
 5026                        continue;
 5027                    }
 5028
 5029                    let text = match indent.kind {
 5030                        IndentKind::Space => " ".repeat(indent.len as usize),
 5031                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5032                    };
 5033                    let point = Point::new(row.0, 0);
 5034                    indent_edits.push((point..point, text));
 5035                }
 5036            }
 5037            editor.edit(indent_edits, cx);
 5038            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5039                format.detach_and_log_err(cx);
 5040            }
 5041        });
 5042    }
 5043
 5044    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5045        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5046            original_indent_columns: Vec::new(),
 5047        });
 5048        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5049    }
 5050
 5051    fn insert_with_autoindent_mode(
 5052        &mut self,
 5053        text: &str,
 5054        autoindent_mode: Option<AutoindentMode>,
 5055        window: &mut Window,
 5056        cx: &mut Context<Self>,
 5057    ) {
 5058        if self.read_only(cx) {
 5059            return;
 5060        }
 5061
 5062        let text: Arc<str> = text.into();
 5063        self.transact(window, cx, |this, window, cx| {
 5064            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5065            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5066                let anchors = {
 5067                    let snapshot = buffer.read(cx);
 5068                    old_selections
 5069                        .iter()
 5070                        .map(|s| {
 5071                            let anchor = snapshot.anchor_after(s.head());
 5072                            s.map(|_| anchor)
 5073                        })
 5074                        .collect::<Vec<_>>()
 5075                };
 5076                buffer.edit(
 5077                    old_selections
 5078                        .iter()
 5079                        .map(|s| (s.start..s.end, text.clone())),
 5080                    autoindent_mode,
 5081                    cx,
 5082                );
 5083                anchors
 5084            });
 5085
 5086            this.change_selections(Default::default(), window, cx, |s| {
 5087                s.select_anchors(selection_anchors);
 5088            });
 5089
 5090            cx.notify();
 5091        });
 5092    }
 5093
 5094    fn trigger_completion_on_input(
 5095        &mut self,
 5096        text: &str,
 5097        trigger_in_words: bool,
 5098        window: &mut Window,
 5099        cx: &mut Context<Self>,
 5100    ) {
 5101        let completions_source = self
 5102            .context_menu
 5103            .borrow()
 5104            .as_ref()
 5105            .and_then(|menu| match menu {
 5106                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5107                CodeContextMenu::CodeActions(_) => None,
 5108            });
 5109
 5110        match completions_source {
 5111            Some(CompletionsMenuSource::Words { .. }) => {
 5112                self.open_or_update_completions_menu(
 5113                    Some(CompletionsMenuSource::Words {
 5114                        ignore_threshold: false,
 5115                    }),
 5116                    None,
 5117                    trigger_in_words,
 5118                    window,
 5119                    cx,
 5120                );
 5121            }
 5122            _ => self.open_or_update_completions_menu(
 5123                None,
 5124                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5125                true,
 5126                window,
 5127                cx,
 5128            ),
 5129        }
 5130    }
 5131
 5132    /// If any empty selections is touching the start of its innermost containing autoclose
 5133    /// region, expand it to select the brackets.
 5134    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5135        let selections = self
 5136            .selections
 5137            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5138        let buffer = self.buffer.read(cx).read(cx);
 5139        let new_selections = self
 5140            .selections_with_autoclose_regions(selections, &buffer)
 5141            .map(|(mut selection, region)| {
 5142                if !selection.is_empty() {
 5143                    return selection;
 5144                }
 5145
 5146                if let Some(region) = region {
 5147                    let mut range = region.range.to_offset(&buffer);
 5148                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5149                        range.start -= region.pair.start.len();
 5150                        if buffer.contains_str_at(range.start, &region.pair.start)
 5151                            && buffer.contains_str_at(range.end, &region.pair.end)
 5152                        {
 5153                            range.end += region.pair.end.len();
 5154                            selection.start = range.start;
 5155                            selection.end = range.end;
 5156
 5157                            return selection;
 5158                        }
 5159                    }
 5160                }
 5161
 5162                let always_treat_brackets_as_autoclosed = buffer
 5163                    .language_settings_at(selection.start, cx)
 5164                    .always_treat_brackets_as_autoclosed;
 5165
 5166                if !always_treat_brackets_as_autoclosed {
 5167                    return selection;
 5168                }
 5169
 5170                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5171                    for (pair, enabled) in scope.brackets() {
 5172                        if !enabled || !pair.close {
 5173                            continue;
 5174                        }
 5175
 5176                        if buffer.contains_str_at(selection.start, &pair.end) {
 5177                            let pair_start_len = pair.start.len();
 5178                            if buffer.contains_str_at(
 5179                                selection.start.saturating_sub_usize(pair_start_len),
 5180                                &pair.start,
 5181                            ) {
 5182                                selection.start -= pair_start_len;
 5183                                selection.end += pair.end.len();
 5184
 5185                                return selection;
 5186                            }
 5187                        }
 5188                    }
 5189                }
 5190
 5191                selection
 5192            })
 5193            .collect();
 5194
 5195        drop(buffer);
 5196        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5197            selections.select(new_selections)
 5198        });
 5199    }
 5200
 5201    /// Iterate the given selections, and for each one, find the smallest surrounding
 5202    /// autoclose region. This uses the ordering of the selections and the autoclose
 5203    /// regions to avoid repeated comparisons.
 5204    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5205        &'a self,
 5206        selections: impl IntoIterator<Item = Selection<D>>,
 5207        buffer: &'a MultiBufferSnapshot,
 5208    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5209        let mut i = 0;
 5210        let mut regions = self.autoclose_regions.as_slice();
 5211        selections.into_iter().map(move |selection| {
 5212            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5213
 5214            let mut enclosing = None;
 5215            while let Some(pair_state) = regions.get(i) {
 5216                if pair_state.range.end.to_offset(buffer) < range.start {
 5217                    regions = &regions[i + 1..];
 5218                    i = 0;
 5219                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5220                    break;
 5221                } else {
 5222                    if pair_state.selection_id == selection.id {
 5223                        enclosing = Some(pair_state);
 5224                    }
 5225                    i += 1;
 5226                }
 5227            }
 5228
 5229            (selection, enclosing)
 5230        })
 5231    }
 5232
 5233    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5234    fn invalidate_autoclose_regions(
 5235        &mut self,
 5236        mut selections: &[Selection<Anchor>],
 5237        buffer: &MultiBufferSnapshot,
 5238    ) {
 5239        self.autoclose_regions.retain(|state| {
 5240            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5241                return false;
 5242            }
 5243
 5244            let mut i = 0;
 5245            while let Some(selection) = selections.get(i) {
 5246                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5247                    selections = &selections[1..];
 5248                    continue;
 5249                }
 5250                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5251                    break;
 5252                }
 5253                if selection.id == state.selection_id {
 5254                    return true;
 5255                } else {
 5256                    i += 1;
 5257                }
 5258            }
 5259            false
 5260        });
 5261    }
 5262
 5263    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5264        let offset = position.to_offset(buffer);
 5265        let (word_range, kind) =
 5266            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5267        if offset > word_range.start && kind == Some(CharKind::Word) {
 5268            Some(
 5269                buffer
 5270                    .text_for_range(word_range.start..offset)
 5271                    .collect::<String>(),
 5272            )
 5273        } else {
 5274            None
 5275        }
 5276    }
 5277
 5278    pub fn visible_excerpts(
 5279        &self,
 5280        lsp_related_only: bool,
 5281        cx: &mut Context<Editor>,
 5282    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5283        let project = self.project().cloned();
 5284        let multi_buffer = self.buffer().read(cx);
 5285        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5286        let multi_buffer_visible_start = self
 5287            .scroll_manager
 5288            .anchor()
 5289            .anchor
 5290            .to_point(&multi_buffer_snapshot);
 5291        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5292            multi_buffer_visible_start
 5293                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5294            Bias::Left,
 5295        );
 5296        multi_buffer_snapshot
 5297            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5298            .into_iter()
 5299            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5300            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5301                if !lsp_related_only {
 5302                    return Some((
 5303                        excerpt_id,
 5304                        (
 5305                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5306                            buffer.version().clone(),
 5307                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5308                        ),
 5309                    ));
 5310                }
 5311
 5312                let project = project.as_ref()?.read(cx);
 5313                let buffer_file = project::File::from_dyn(buffer.file())?;
 5314                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5315                let worktree_entry = buffer_worktree
 5316                    .read(cx)
 5317                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5318                if worktree_entry.is_ignored {
 5319                    None
 5320                } else {
 5321                    Some((
 5322                        excerpt_id,
 5323                        (
 5324                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5325                            buffer.version().clone(),
 5326                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5327                        ),
 5328                    ))
 5329                }
 5330            })
 5331            .collect()
 5332    }
 5333
 5334    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5335        TextLayoutDetails {
 5336            text_system: window.text_system().clone(),
 5337            editor_style: self.style.clone().unwrap(),
 5338            rem_size: window.rem_size(),
 5339            scroll_anchor: self.scroll_manager.anchor(),
 5340            visible_rows: self.visible_line_count(),
 5341            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5342        }
 5343    }
 5344
 5345    fn trigger_on_type_formatting(
 5346        &self,
 5347        input: String,
 5348        window: &mut Window,
 5349        cx: &mut Context<Self>,
 5350    ) -> Option<Task<Result<()>>> {
 5351        if input.chars().count() != 1 {
 5352            return None;
 5353        }
 5354
 5355        let project = self.project()?;
 5356        let position = self.selections.newest_anchor().head();
 5357        let (buffer, buffer_position) = self
 5358            .buffer
 5359            .read(cx)
 5360            .text_anchor_for_position(position, cx)?;
 5361
 5362        let settings = language_settings::language_settings(
 5363            buffer
 5364                .read(cx)
 5365                .language_at(buffer_position)
 5366                .map(|l| l.name()),
 5367            buffer.read(cx).file(),
 5368            cx,
 5369        );
 5370        if !settings.use_on_type_format {
 5371            return None;
 5372        }
 5373
 5374        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5375        // hence we do LSP request & edit on host side only — add formats to host's history.
 5376        let push_to_lsp_host_history = true;
 5377        // If this is not the host, append its history with new edits.
 5378        let push_to_client_history = project.read(cx).is_via_collab();
 5379
 5380        let on_type_formatting = project.update(cx, |project, cx| {
 5381            project.on_type_format(
 5382                buffer.clone(),
 5383                buffer_position,
 5384                input,
 5385                push_to_lsp_host_history,
 5386                cx,
 5387            )
 5388        });
 5389        Some(cx.spawn_in(window, async move |editor, cx| {
 5390            if let Some(transaction) = on_type_formatting.await? {
 5391                if push_to_client_history {
 5392                    buffer
 5393                        .update(cx, |buffer, _| {
 5394                            buffer.push_transaction(transaction, Instant::now());
 5395                            buffer.finalize_last_transaction();
 5396                        })
 5397                        .ok();
 5398                }
 5399                editor.update(cx, |editor, cx| {
 5400                    editor.refresh_document_highlights(cx);
 5401                })?;
 5402            }
 5403            Ok(())
 5404        }))
 5405    }
 5406
 5407    pub fn show_word_completions(
 5408        &mut self,
 5409        _: &ShowWordCompletions,
 5410        window: &mut Window,
 5411        cx: &mut Context<Self>,
 5412    ) {
 5413        self.open_or_update_completions_menu(
 5414            Some(CompletionsMenuSource::Words {
 5415                ignore_threshold: true,
 5416            }),
 5417            None,
 5418            false,
 5419            window,
 5420            cx,
 5421        );
 5422    }
 5423
 5424    pub fn show_completions(
 5425        &mut self,
 5426        _: &ShowCompletions,
 5427        window: &mut Window,
 5428        cx: &mut Context<Self>,
 5429    ) {
 5430        self.open_or_update_completions_menu(None, None, false, window, cx);
 5431    }
 5432
 5433    fn open_or_update_completions_menu(
 5434        &mut self,
 5435        requested_source: Option<CompletionsMenuSource>,
 5436        trigger: Option<String>,
 5437        trigger_in_words: bool,
 5438        window: &mut Window,
 5439        cx: &mut Context<Self>,
 5440    ) {
 5441        if self.pending_rename.is_some() {
 5442            return;
 5443        }
 5444
 5445        let completions_source = self
 5446            .context_menu
 5447            .borrow()
 5448            .as_ref()
 5449            .and_then(|menu| match menu {
 5450                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5451                CodeContextMenu::CodeActions(_) => None,
 5452            });
 5453
 5454        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5455
 5456        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5457        // inserted and selected. To handle that case, the start of the selection is used so that
 5458        // the menu starts with all choices.
 5459        let position = self
 5460            .selections
 5461            .newest_anchor()
 5462            .start
 5463            .bias_right(&multibuffer_snapshot);
 5464        if position.diff_base_anchor.is_some() {
 5465            return;
 5466        }
 5467        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5468        let Some(buffer) = buffer_position
 5469            .text_anchor
 5470            .buffer_id
 5471            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5472        else {
 5473            return;
 5474        };
 5475        let buffer_snapshot = buffer.read(cx).snapshot();
 5476
 5477        let menu_is_open = matches!(
 5478            self.context_menu.borrow().as_ref(),
 5479            Some(CodeContextMenu::Completions(_))
 5480        );
 5481
 5482        let language = buffer_snapshot
 5483            .language_at(buffer_position.text_anchor)
 5484            .map(|language| language.name());
 5485
 5486        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5487        let completion_settings = language_settings.completions.clone();
 5488
 5489        let show_completions_on_input = self
 5490            .show_completions_on_input_override
 5491            .unwrap_or(language_settings.show_completions_on_input);
 5492        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5493            return;
 5494        }
 5495
 5496        let query: Option<Arc<String>> =
 5497            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5498                .map(|query| query.into());
 5499
 5500        drop(multibuffer_snapshot);
 5501
 5502        // Hide the current completions menu when query is empty. Without this, cached
 5503        // completions from before the trigger char may be reused (#32774).
 5504        if query.is_none() && menu_is_open {
 5505            self.hide_context_menu(window, cx);
 5506        }
 5507
 5508        let mut ignore_word_threshold = false;
 5509        let provider = match requested_source {
 5510            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5511            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5512                ignore_word_threshold = ignore_threshold;
 5513                None
 5514            }
 5515            Some(CompletionsMenuSource::SnippetChoices)
 5516            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5517                log::error!("bug: SnippetChoices requested_source is not handled");
 5518                None
 5519            }
 5520        };
 5521
 5522        let sort_completions = provider
 5523            .as_ref()
 5524            .is_some_and(|provider| provider.sort_completions());
 5525
 5526        let filter_completions = provider
 5527            .as_ref()
 5528            .is_none_or(|provider| provider.filter_completions());
 5529
 5530        let was_snippets_only = matches!(
 5531            completions_source,
 5532            Some(CompletionsMenuSource::SnippetsOnly)
 5533        );
 5534
 5535        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5536            if filter_completions {
 5537                menu.filter(
 5538                    query.clone().unwrap_or_default(),
 5539                    buffer_position.text_anchor,
 5540                    &buffer,
 5541                    provider.clone(),
 5542                    window,
 5543                    cx,
 5544                );
 5545            }
 5546            // When `is_incomplete` is false, no need to re-query completions when the current query
 5547            // is a suffix of the initial query.
 5548            let was_complete = !menu.is_incomplete;
 5549            if was_complete && !was_snippets_only {
 5550                // If the new query is a suffix of the old query (typing more characters) and
 5551                // the previous result was complete, the existing completions can be filtered.
 5552                //
 5553                // Note that snippet completions are always complete.
 5554                let query_matches = match (&menu.initial_query, &query) {
 5555                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5556                    (None, _) => true,
 5557                    _ => false,
 5558                };
 5559                if query_matches {
 5560                    let position_matches = if menu.initial_position == position {
 5561                        true
 5562                    } else {
 5563                        let snapshot = self.buffer.read(cx).read(cx);
 5564                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5565                    };
 5566                    if position_matches {
 5567                        return;
 5568                    }
 5569                }
 5570            }
 5571        };
 5572
 5573        let Anchor {
 5574            excerpt_id: buffer_excerpt_id,
 5575            text_anchor: buffer_position,
 5576            ..
 5577        } = buffer_position;
 5578
 5579        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5580            buffer_snapshot.surrounding_word(buffer_position, None)
 5581        {
 5582            let word_to_exclude = buffer_snapshot
 5583                .text_for_range(word_range.clone())
 5584                .collect::<String>();
 5585            (
 5586                buffer_snapshot.anchor_before(word_range.start)
 5587                    ..buffer_snapshot.anchor_after(buffer_position),
 5588                Some(word_to_exclude),
 5589            )
 5590        } else {
 5591            (buffer_position..buffer_position, None)
 5592        };
 5593
 5594        let show_completion_documentation = buffer_snapshot
 5595            .settings_at(buffer_position, cx)
 5596            .show_completion_documentation;
 5597
 5598        // The document can be large, so stay in reasonable bounds when searching for words,
 5599        // otherwise completion pop-up might be slow to appear.
 5600        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5601        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5602        let min_word_search = buffer_snapshot.clip_point(
 5603            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5604            Bias::Left,
 5605        );
 5606        let max_word_search = buffer_snapshot.clip_point(
 5607            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5608            Bias::Right,
 5609        );
 5610        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5611            ..buffer_snapshot.point_to_offset(max_word_search);
 5612
 5613        let skip_digits = query
 5614            .as_ref()
 5615            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5616
 5617        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5618            trigger.as_ref().is_none_or(|trigger| {
 5619                provider.is_completion_trigger(
 5620                    &buffer,
 5621                    position.text_anchor,
 5622                    trigger,
 5623                    trigger_in_words,
 5624                    cx,
 5625                )
 5626            })
 5627        });
 5628
 5629        let provider_responses = if let Some(provider) = &provider
 5630            && load_provider_completions
 5631        {
 5632            let trigger_character =
 5633                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5634            let completion_context = CompletionContext {
 5635                trigger_kind: match &trigger_character {
 5636                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5637                    None => CompletionTriggerKind::INVOKED,
 5638                },
 5639                trigger_character,
 5640            };
 5641
 5642            provider.completions(
 5643                buffer_excerpt_id,
 5644                &buffer,
 5645                buffer_position,
 5646                completion_context,
 5647                window,
 5648                cx,
 5649            )
 5650        } else {
 5651            Task::ready(Ok(Vec::new()))
 5652        };
 5653
 5654        let load_word_completions = if !self.word_completions_enabled {
 5655            false
 5656        } else if requested_source
 5657            == Some(CompletionsMenuSource::Words {
 5658                ignore_threshold: true,
 5659            })
 5660        {
 5661            true
 5662        } else {
 5663            load_provider_completions
 5664                && completion_settings.words != WordsCompletionMode::Disabled
 5665                && (ignore_word_threshold || {
 5666                    let words_min_length = completion_settings.words_min_length;
 5667                    // check whether word has at least `words_min_length` characters
 5668                    let query_chars = query.iter().flat_map(|q| q.chars());
 5669                    query_chars.take(words_min_length).count() == words_min_length
 5670                })
 5671        };
 5672
 5673        let mut words = if load_word_completions {
 5674            cx.background_spawn({
 5675                let buffer_snapshot = buffer_snapshot.clone();
 5676                async move {
 5677                    buffer_snapshot.words_in_range(WordsQuery {
 5678                        fuzzy_contents: None,
 5679                        range: word_search_range,
 5680                        skip_digits,
 5681                    })
 5682                }
 5683            })
 5684        } else {
 5685            Task::ready(BTreeMap::default())
 5686        };
 5687
 5688        let snippets = if let Some(provider) = &provider
 5689            && provider.show_snippets()
 5690            && let Some(project) = self.project()
 5691        {
 5692            let char_classifier = buffer_snapshot
 5693                .char_classifier_at(buffer_position)
 5694                .scope_context(Some(CharScopeContext::Completion));
 5695            project.update(cx, |project, cx| {
 5696                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5697            })
 5698        } else {
 5699            Task::ready(Ok(CompletionResponse {
 5700                completions: Vec::new(),
 5701                display_options: Default::default(),
 5702                is_incomplete: false,
 5703            }))
 5704        };
 5705
 5706        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5707
 5708        let id = post_inc(&mut self.next_completion_id);
 5709        let task = cx.spawn_in(window, async move |editor, cx| {
 5710            let Ok(()) = editor.update(cx, |this, _| {
 5711                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5712            }) else {
 5713                return;
 5714            };
 5715
 5716            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5717            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5718            let mut completions = Vec::new();
 5719            let mut is_incomplete = false;
 5720            let mut display_options: Option<CompletionDisplayOptions> = None;
 5721            if let Some(provider_responses) = provider_responses.await.log_err()
 5722                && !provider_responses.is_empty()
 5723            {
 5724                for response in provider_responses {
 5725                    completions.extend(response.completions);
 5726                    is_incomplete = is_incomplete || response.is_incomplete;
 5727                    match display_options.as_mut() {
 5728                        None => {
 5729                            display_options = Some(response.display_options);
 5730                        }
 5731                        Some(options) => options.merge(&response.display_options),
 5732                    }
 5733                }
 5734                if completion_settings.words == WordsCompletionMode::Fallback {
 5735                    words = Task::ready(BTreeMap::default());
 5736                }
 5737            }
 5738            let display_options = display_options.unwrap_or_default();
 5739
 5740            let mut words = words.await;
 5741            if let Some(word_to_exclude) = &word_to_exclude {
 5742                words.remove(word_to_exclude);
 5743            }
 5744            for lsp_completion in &completions {
 5745                words.remove(&lsp_completion.new_text);
 5746            }
 5747            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5748                replace_range: word_replace_range.clone(),
 5749                new_text: word.clone(),
 5750                label: CodeLabel::plain(word, None),
 5751                match_start: None,
 5752                snippet_deduplication_key: None,
 5753                icon_path: None,
 5754                documentation: None,
 5755                source: CompletionSource::BufferWord {
 5756                    word_range,
 5757                    resolved: false,
 5758                },
 5759                insert_text_mode: Some(InsertTextMode::AS_IS),
 5760                confirm: None,
 5761            }));
 5762
 5763            completions.extend(
 5764                snippets
 5765                    .await
 5766                    .into_iter()
 5767                    .flat_map(|response| response.completions),
 5768            );
 5769
 5770            let menu = if completions.is_empty() {
 5771                None
 5772            } else {
 5773                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5774                    let languages = editor
 5775                        .workspace
 5776                        .as_ref()
 5777                        .and_then(|(workspace, _)| workspace.upgrade())
 5778                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5779                    let menu = CompletionsMenu::new(
 5780                        id,
 5781                        requested_source.unwrap_or(if load_provider_completions {
 5782                            CompletionsMenuSource::Normal
 5783                        } else {
 5784                            CompletionsMenuSource::SnippetsOnly
 5785                        }),
 5786                        sort_completions,
 5787                        show_completion_documentation,
 5788                        position,
 5789                        query.clone(),
 5790                        is_incomplete,
 5791                        buffer.clone(),
 5792                        completions.into(),
 5793                        editor
 5794                            .context_menu()
 5795                            .borrow_mut()
 5796                            .as_ref()
 5797                            .map(|menu| menu.primary_scroll_handle()),
 5798                        display_options,
 5799                        snippet_sort_order,
 5800                        languages,
 5801                        language,
 5802                        cx,
 5803                    );
 5804
 5805                    let query = if filter_completions { query } else { None };
 5806                    let matches_task = menu.do_async_filtering(
 5807                        query.unwrap_or_default(),
 5808                        buffer_position,
 5809                        &buffer,
 5810                        cx,
 5811                    );
 5812                    (menu, matches_task)
 5813                }) else {
 5814                    return;
 5815                };
 5816
 5817                let matches = matches_task.await;
 5818
 5819                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5820                    // Newer menu already set, so exit.
 5821                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5822                        editor.context_menu.borrow().as_ref()
 5823                        && prev_menu.id > id
 5824                    {
 5825                        return;
 5826                    };
 5827
 5828                    // Only valid to take prev_menu because either the new menu is immediately set
 5829                    // below, or the menu is hidden.
 5830                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5831                        editor.context_menu.borrow_mut().take()
 5832                    {
 5833                        let position_matches =
 5834                            if prev_menu.initial_position == menu.initial_position {
 5835                                true
 5836                            } else {
 5837                                let snapshot = editor.buffer.read(cx).read(cx);
 5838                                prev_menu.initial_position.to_offset(&snapshot)
 5839                                    == menu.initial_position.to_offset(&snapshot)
 5840                            };
 5841                        if position_matches {
 5842                            // Preserve markdown cache before `set_filter_results` because it will
 5843                            // try to populate the documentation cache.
 5844                            menu.preserve_markdown_cache(prev_menu);
 5845                        }
 5846                    };
 5847
 5848                    menu.set_filter_results(matches, provider, window, cx);
 5849                }) else {
 5850                    return;
 5851                };
 5852
 5853                menu.visible().then_some(menu)
 5854            };
 5855
 5856            editor
 5857                .update_in(cx, |editor, window, cx| {
 5858                    if editor.focus_handle.is_focused(window)
 5859                        && let Some(menu) = menu
 5860                    {
 5861                        *editor.context_menu.borrow_mut() =
 5862                            Some(CodeContextMenu::Completions(menu));
 5863
 5864                        crate::hover_popover::hide_hover(editor, cx);
 5865                        if editor.show_edit_predictions_in_menu() {
 5866                            editor.update_visible_edit_prediction(window, cx);
 5867                        } else {
 5868                            editor.discard_edit_prediction(false, cx);
 5869                        }
 5870
 5871                        cx.notify();
 5872                        return;
 5873                    }
 5874
 5875                    if editor.completion_tasks.len() <= 1 {
 5876                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5877                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5878                        // If it was already hidden and we don't show edit predictions in the menu,
 5879                        // we should also show the edit prediction when available.
 5880                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5881                            editor.update_visible_edit_prediction(window, cx);
 5882                        }
 5883                    }
 5884                })
 5885                .ok();
 5886        });
 5887
 5888        self.completion_tasks.push((id, task));
 5889    }
 5890
 5891    #[cfg(feature = "test-support")]
 5892    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5893        let menu = self.context_menu.borrow();
 5894        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5895            let completions = menu.completions.borrow();
 5896            Some(completions.to_vec())
 5897        } else {
 5898            None
 5899        }
 5900    }
 5901
 5902    pub fn with_completions_menu_matching_id<R>(
 5903        &self,
 5904        id: CompletionId,
 5905        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5906    ) -> R {
 5907        let mut context_menu = self.context_menu.borrow_mut();
 5908        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5909            return f(None);
 5910        };
 5911        if completions_menu.id != id {
 5912            return f(None);
 5913        }
 5914        f(Some(completions_menu))
 5915    }
 5916
 5917    pub fn confirm_completion(
 5918        &mut self,
 5919        action: &ConfirmCompletion,
 5920        window: &mut Window,
 5921        cx: &mut Context<Self>,
 5922    ) -> Option<Task<Result<()>>> {
 5923        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5924        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5925    }
 5926
 5927    pub fn confirm_completion_insert(
 5928        &mut self,
 5929        _: &ConfirmCompletionInsert,
 5930        window: &mut Window,
 5931        cx: &mut Context<Self>,
 5932    ) -> Option<Task<Result<()>>> {
 5933        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5934        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5935    }
 5936
 5937    pub fn confirm_completion_replace(
 5938        &mut self,
 5939        _: &ConfirmCompletionReplace,
 5940        window: &mut Window,
 5941        cx: &mut Context<Self>,
 5942    ) -> Option<Task<Result<()>>> {
 5943        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5944        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5945    }
 5946
 5947    pub fn compose_completion(
 5948        &mut self,
 5949        action: &ComposeCompletion,
 5950        window: &mut Window,
 5951        cx: &mut Context<Self>,
 5952    ) -> Option<Task<Result<()>>> {
 5953        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5954        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5955    }
 5956
 5957    fn do_completion(
 5958        &mut self,
 5959        item_ix: Option<usize>,
 5960        intent: CompletionIntent,
 5961        window: &mut Window,
 5962        cx: &mut Context<Editor>,
 5963    ) -> Option<Task<Result<()>>> {
 5964        use language::ToOffset as _;
 5965
 5966        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5967        else {
 5968            return None;
 5969        };
 5970
 5971        let candidate_id = {
 5972            let entries = completions_menu.entries.borrow();
 5973            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5974            if self.show_edit_predictions_in_menu() {
 5975                self.discard_edit_prediction(true, cx);
 5976            }
 5977            mat.candidate_id
 5978        };
 5979
 5980        let completion = completions_menu
 5981            .completions
 5982            .borrow()
 5983            .get(candidate_id)?
 5984            .clone();
 5985        cx.stop_propagation();
 5986
 5987        let buffer_handle = completions_menu.buffer.clone();
 5988
 5989        let CompletionEdit {
 5990            new_text,
 5991            snippet,
 5992            replace_range,
 5993        } = process_completion_for_edit(
 5994            &completion,
 5995            intent,
 5996            &buffer_handle,
 5997            &completions_menu.initial_position.text_anchor,
 5998            cx,
 5999        );
 6000
 6001        let buffer = buffer_handle.read(cx);
 6002        let snapshot = self.buffer.read(cx).snapshot(cx);
 6003        let newest_anchor = self.selections.newest_anchor();
 6004        let replace_range_multibuffer = {
 6005            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6006            excerpt.map_range_from_buffer(replace_range.clone())
 6007        };
 6008        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6009            return None;
 6010        }
 6011
 6012        let old_text = buffer
 6013            .text_for_range(replace_range.clone())
 6014            .collect::<String>();
 6015        let lookbehind = newest_anchor
 6016            .start
 6017            .text_anchor
 6018            .to_offset(buffer)
 6019            .saturating_sub(replace_range.start.0);
 6020        let lookahead = replace_range
 6021            .end
 6022            .0
 6023            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6024        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6025        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6026
 6027        let selections = self
 6028            .selections
 6029            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6030        let mut ranges = Vec::new();
 6031        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6032
 6033        for selection in &selections {
 6034            let range = if selection.id == newest_anchor.id {
 6035                replace_range_multibuffer.clone()
 6036            } else {
 6037                let mut range = selection.range();
 6038
 6039                // if prefix is present, don't duplicate it
 6040                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6041                    range.start = range.start.saturating_sub_usize(lookbehind);
 6042
 6043                    // if suffix is also present, mimic the newest cursor and replace it
 6044                    if selection.id != newest_anchor.id
 6045                        && snapshot.contains_str_at(range.end, suffix)
 6046                    {
 6047                        range.end += lookahead;
 6048                    }
 6049                }
 6050                range
 6051            };
 6052
 6053            ranges.push(range.clone());
 6054
 6055            if !self.linked_edit_ranges.is_empty() {
 6056                let start_anchor = snapshot.anchor_before(range.start);
 6057                let end_anchor = snapshot.anchor_after(range.end);
 6058                if let Some(ranges) = self
 6059                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6060                {
 6061                    for (buffer, edits) in ranges {
 6062                        linked_edits
 6063                            .entry(buffer.clone())
 6064                            .or_default()
 6065                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6066                    }
 6067                }
 6068            }
 6069        }
 6070
 6071        let common_prefix_len = old_text
 6072            .chars()
 6073            .zip(new_text.chars())
 6074            .take_while(|(a, b)| a == b)
 6075            .map(|(a, _)| a.len_utf8())
 6076            .sum::<usize>();
 6077
 6078        cx.emit(EditorEvent::InputHandled {
 6079            utf16_range_to_replace: None,
 6080            text: new_text[common_prefix_len..].into(),
 6081        });
 6082
 6083        self.transact(window, cx, |editor, window, cx| {
 6084            if let Some(mut snippet) = snippet {
 6085                snippet.text = new_text.to_string();
 6086                editor
 6087                    .insert_snippet(&ranges, snippet, window, cx)
 6088                    .log_err();
 6089            } else {
 6090                editor.buffer.update(cx, |multi_buffer, cx| {
 6091                    let auto_indent = match completion.insert_text_mode {
 6092                        Some(InsertTextMode::AS_IS) => None,
 6093                        _ => editor.autoindent_mode.clone(),
 6094                    };
 6095                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6096                    multi_buffer.edit(edits, auto_indent, cx);
 6097                });
 6098            }
 6099            for (buffer, edits) in linked_edits {
 6100                buffer.update(cx, |buffer, cx| {
 6101                    let snapshot = buffer.snapshot();
 6102                    let edits = edits
 6103                        .into_iter()
 6104                        .map(|(range, text)| {
 6105                            use text::ToPoint as TP;
 6106                            let end_point = TP::to_point(&range.end, &snapshot);
 6107                            let start_point = TP::to_point(&range.start, &snapshot);
 6108                            (start_point..end_point, text)
 6109                        })
 6110                        .sorted_by_key(|(range, _)| range.start);
 6111                    buffer.edit(edits, None, cx);
 6112                })
 6113            }
 6114
 6115            editor.refresh_edit_prediction(true, false, window, cx);
 6116        });
 6117        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6118
 6119        let show_new_completions_on_confirm = completion
 6120            .confirm
 6121            .as_ref()
 6122            .is_some_and(|confirm| confirm(intent, window, cx));
 6123        if show_new_completions_on_confirm {
 6124            self.open_or_update_completions_menu(None, None, false, window, cx);
 6125        }
 6126
 6127        let provider = self.completion_provider.as_ref()?;
 6128
 6129        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6130        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6131            let CompletionSource::Lsp {
 6132                lsp_completion,
 6133                server_id,
 6134                ..
 6135            } = &completion.source
 6136            else {
 6137                return None;
 6138            };
 6139            let lsp_command = lsp_completion.command.as_ref()?;
 6140            let available_commands = lsp_store
 6141                .read(cx)
 6142                .lsp_server_capabilities
 6143                .get(server_id)
 6144                .and_then(|server_capabilities| {
 6145                    server_capabilities
 6146                        .execute_command_provider
 6147                        .as_ref()
 6148                        .map(|options| options.commands.as_slice())
 6149                })?;
 6150            if available_commands.contains(&lsp_command.command) {
 6151                Some(CodeAction {
 6152                    server_id: *server_id,
 6153                    range: language::Anchor::MIN..language::Anchor::MIN,
 6154                    lsp_action: LspAction::Command(lsp_command.clone()),
 6155                    resolved: false,
 6156                })
 6157            } else {
 6158                None
 6159            }
 6160        });
 6161
 6162        drop(completion);
 6163        let apply_edits = provider.apply_additional_edits_for_completion(
 6164            buffer_handle.clone(),
 6165            completions_menu.completions.clone(),
 6166            candidate_id,
 6167            true,
 6168            cx,
 6169        );
 6170
 6171        let editor_settings = EditorSettings::get_global(cx);
 6172        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6173            // After the code completion is finished, users often want to know what signatures are needed.
 6174            // so we should automatically call signature_help
 6175            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6176        }
 6177
 6178        Some(cx.spawn_in(window, async move |editor, cx| {
 6179            apply_edits.await?;
 6180
 6181            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6182                let title = command.lsp_action.title().to_owned();
 6183                let project_transaction = lsp_store
 6184                    .update(cx, |lsp_store, cx| {
 6185                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6186                    })?
 6187                    .await
 6188                    .context("applying post-completion command")?;
 6189                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6190                    Self::open_project_transaction(
 6191                        &editor,
 6192                        workspace.downgrade(),
 6193                        project_transaction,
 6194                        title,
 6195                        cx,
 6196                    )
 6197                    .await?;
 6198                }
 6199            }
 6200
 6201            Ok(())
 6202        }))
 6203    }
 6204
 6205    pub fn toggle_code_actions(
 6206        &mut self,
 6207        action: &ToggleCodeActions,
 6208        window: &mut Window,
 6209        cx: &mut Context<Self>,
 6210    ) {
 6211        let quick_launch = action.quick_launch;
 6212        let mut context_menu = self.context_menu.borrow_mut();
 6213        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6214            if code_actions.deployed_from == action.deployed_from {
 6215                // Toggle if we're selecting the same one
 6216                *context_menu = None;
 6217                cx.notify();
 6218                return;
 6219            } else {
 6220                // Otherwise, clear it and start a new one
 6221                *context_menu = None;
 6222                cx.notify();
 6223            }
 6224        }
 6225        drop(context_menu);
 6226        let snapshot = self.snapshot(window, cx);
 6227        let deployed_from = action.deployed_from.clone();
 6228        let action = action.clone();
 6229        self.completion_tasks.clear();
 6230        self.discard_edit_prediction(false, cx);
 6231
 6232        let multibuffer_point = match &action.deployed_from {
 6233            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6234                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6235            }
 6236            _ => self
 6237                .selections
 6238                .newest::<Point>(&snapshot.display_snapshot)
 6239                .head(),
 6240        };
 6241        let Some((buffer, buffer_row)) = snapshot
 6242            .buffer_snapshot()
 6243            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6244            .and_then(|(buffer_snapshot, range)| {
 6245                self.buffer()
 6246                    .read(cx)
 6247                    .buffer(buffer_snapshot.remote_id())
 6248                    .map(|buffer| (buffer, range.start.row))
 6249            })
 6250        else {
 6251            return;
 6252        };
 6253        let buffer_id = buffer.read(cx).remote_id();
 6254        let tasks = self
 6255            .tasks
 6256            .get(&(buffer_id, buffer_row))
 6257            .map(|t| Arc::new(t.to_owned()));
 6258
 6259        if !self.focus_handle.is_focused(window) {
 6260            return;
 6261        }
 6262        let project = self.project.clone();
 6263
 6264        let code_actions_task = match deployed_from {
 6265            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6266            _ => self.code_actions(buffer_row, window, cx),
 6267        };
 6268
 6269        let runnable_task = match deployed_from {
 6270            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6271            _ => {
 6272                let mut task_context_task = Task::ready(None);
 6273                if let Some(tasks) = &tasks
 6274                    && let Some(project) = project
 6275                {
 6276                    task_context_task =
 6277                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6278                }
 6279
 6280                cx.spawn_in(window, {
 6281                    let buffer = buffer.clone();
 6282                    async move |editor, cx| {
 6283                        let task_context = task_context_task.await;
 6284
 6285                        let resolved_tasks =
 6286                            tasks
 6287                                .zip(task_context.clone())
 6288                                .map(|(tasks, task_context)| ResolvedTasks {
 6289                                    templates: tasks.resolve(&task_context).collect(),
 6290                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6291                                        multibuffer_point.row,
 6292                                        tasks.column,
 6293                                    )),
 6294                                });
 6295                        let debug_scenarios = editor
 6296                            .update(cx, |editor, cx| {
 6297                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6298                            })?
 6299                            .await;
 6300                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6301                    }
 6302                })
 6303            }
 6304        };
 6305
 6306        cx.spawn_in(window, async move |editor, cx| {
 6307            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6308            let code_actions = code_actions_task.await;
 6309            let spawn_straight_away = quick_launch
 6310                && resolved_tasks
 6311                    .as_ref()
 6312                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6313                && code_actions
 6314                    .as_ref()
 6315                    .is_none_or(|actions| actions.is_empty())
 6316                && debug_scenarios.is_empty();
 6317
 6318            editor.update_in(cx, |editor, window, cx| {
 6319                crate::hover_popover::hide_hover(editor, cx);
 6320                let actions = CodeActionContents::new(
 6321                    resolved_tasks,
 6322                    code_actions,
 6323                    debug_scenarios,
 6324                    task_context.unwrap_or_default(),
 6325                );
 6326
 6327                // Don't show the menu if there are no actions available
 6328                if actions.is_empty() {
 6329                    cx.notify();
 6330                    return Task::ready(Ok(()));
 6331                }
 6332
 6333                *editor.context_menu.borrow_mut() =
 6334                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6335                        buffer,
 6336                        actions,
 6337                        selected_item: Default::default(),
 6338                        scroll_handle: UniformListScrollHandle::default(),
 6339                        deployed_from,
 6340                    }));
 6341                cx.notify();
 6342                if spawn_straight_away
 6343                    && let Some(task) = editor.confirm_code_action(
 6344                        &ConfirmCodeAction { item_ix: Some(0) },
 6345                        window,
 6346                        cx,
 6347                    )
 6348                {
 6349                    return task;
 6350                }
 6351
 6352                Task::ready(Ok(()))
 6353            })
 6354        })
 6355        .detach_and_log_err(cx);
 6356    }
 6357
 6358    fn debug_scenarios(
 6359        &mut self,
 6360        resolved_tasks: &Option<ResolvedTasks>,
 6361        buffer: &Entity<Buffer>,
 6362        cx: &mut App,
 6363    ) -> Task<Vec<task::DebugScenario>> {
 6364        maybe!({
 6365            let project = self.project()?;
 6366            let dap_store = project.read(cx).dap_store();
 6367            let mut scenarios = vec![];
 6368            let resolved_tasks = resolved_tasks.as_ref()?;
 6369            let buffer = buffer.read(cx);
 6370            let language = buffer.language()?;
 6371            let file = buffer.file();
 6372            let debug_adapter = language_settings(language.name().into(), file, cx)
 6373                .debuggers
 6374                .first()
 6375                .map(SharedString::from)
 6376                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6377
 6378            dap_store.update(cx, |dap_store, cx| {
 6379                for (_, task) in &resolved_tasks.templates {
 6380                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6381                        task.original_task().clone(),
 6382                        debug_adapter.clone().into(),
 6383                        task.display_label().to_owned().into(),
 6384                        cx,
 6385                    );
 6386                    scenarios.push(maybe_scenario);
 6387                }
 6388            });
 6389            Some(cx.background_spawn(async move {
 6390                futures::future::join_all(scenarios)
 6391                    .await
 6392                    .into_iter()
 6393                    .flatten()
 6394                    .collect::<Vec<_>>()
 6395            }))
 6396        })
 6397        .unwrap_or_else(|| Task::ready(vec![]))
 6398    }
 6399
 6400    fn code_actions(
 6401        &mut self,
 6402        buffer_row: u32,
 6403        window: &mut Window,
 6404        cx: &mut Context<Self>,
 6405    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6406        let mut task = self.code_actions_task.take();
 6407        cx.spawn_in(window, async move |editor, cx| {
 6408            while let Some(prev_task) = task {
 6409                prev_task.await.log_err();
 6410                task = editor
 6411                    .update(cx, |this, _| this.code_actions_task.take())
 6412                    .ok()?;
 6413            }
 6414
 6415            editor
 6416                .update(cx, |editor, cx| {
 6417                    editor
 6418                        .available_code_actions
 6419                        .clone()
 6420                        .and_then(|(location, code_actions)| {
 6421                            let snapshot = location.buffer.read(cx).snapshot();
 6422                            let point_range = location.range.to_point(&snapshot);
 6423                            let point_range = point_range.start.row..=point_range.end.row;
 6424                            if point_range.contains(&buffer_row) {
 6425                                Some(code_actions)
 6426                            } else {
 6427                                None
 6428                            }
 6429                        })
 6430                })
 6431                .ok()
 6432                .flatten()
 6433        })
 6434    }
 6435
 6436    pub fn confirm_code_action(
 6437        &mut self,
 6438        action: &ConfirmCodeAction,
 6439        window: &mut Window,
 6440        cx: &mut Context<Self>,
 6441    ) -> Option<Task<Result<()>>> {
 6442        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6443
 6444        let actions_menu =
 6445            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6446                menu
 6447            } else {
 6448                return None;
 6449            };
 6450
 6451        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6452        let action = actions_menu.actions.get(action_ix)?;
 6453        let title = action.label();
 6454        let buffer = actions_menu.buffer;
 6455        let workspace = self.workspace()?;
 6456
 6457        match action {
 6458            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6459                workspace.update(cx, |workspace, cx| {
 6460                    workspace.schedule_resolved_task(
 6461                        task_source_kind,
 6462                        resolved_task,
 6463                        false,
 6464                        window,
 6465                        cx,
 6466                    );
 6467
 6468                    Some(Task::ready(Ok(())))
 6469                })
 6470            }
 6471            CodeActionsItem::CodeAction {
 6472                excerpt_id,
 6473                action,
 6474                provider,
 6475            } => {
 6476                let apply_code_action =
 6477                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6478                let workspace = workspace.downgrade();
 6479                Some(cx.spawn_in(window, async move |editor, cx| {
 6480                    let project_transaction = apply_code_action.await?;
 6481                    Self::open_project_transaction(
 6482                        &editor,
 6483                        workspace,
 6484                        project_transaction,
 6485                        title,
 6486                        cx,
 6487                    )
 6488                    .await
 6489                }))
 6490            }
 6491            CodeActionsItem::DebugScenario(scenario) => {
 6492                let context = actions_menu.actions.context;
 6493
 6494                workspace.update(cx, |workspace, cx| {
 6495                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6496                    workspace.start_debug_session(
 6497                        scenario,
 6498                        context,
 6499                        Some(buffer),
 6500                        None,
 6501                        window,
 6502                        cx,
 6503                    );
 6504                });
 6505                Some(Task::ready(Ok(())))
 6506            }
 6507        }
 6508    }
 6509
 6510    fn open_transaction_for_hidden_buffers(
 6511        workspace: Entity<Workspace>,
 6512        transaction: ProjectTransaction,
 6513        title: String,
 6514        window: &mut Window,
 6515        cx: &mut Context<Self>,
 6516    ) {
 6517        if transaction.0.is_empty() {
 6518            return;
 6519        }
 6520
 6521        let edited_buffers_already_open = {
 6522            let other_editors: Vec<Entity<Editor>> = workspace
 6523                .read(cx)
 6524                .panes()
 6525                .iter()
 6526                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 6527                .filter(|editor| editor.entity_id() != cx.entity_id())
 6528                .collect();
 6529
 6530            transaction.0.keys().all(|buffer| {
 6531                other_editors.iter().any(|editor| {
 6532                    let multi_buffer = editor.read(cx).buffer();
 6533                    multi_buffer.read(cx).is_singleton()
 6534                        && multi_buffer
 6535                            .read(cx)
 6536                            .as_singleton()
 6537                            .map_or(false, |singleton| {
 6538                                singleton.entity_id() == buffer.entity_id()
 6539                            })
 6540                })
 6541            })
 6542        };
 6543        if !edited_buffers_already_open {
 6544            let workspace = workspace.downgrade();
 6545            cx.defer_in(window, move |_, window, cx| {
 6546                cx.spawn_in(window, async move |editor, cx| {
 6547                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 6548                        .await
 6549                        .ok()
 6550                })
 6551                .detach();
 6552            });
 6553        }
 6554    }
 6555
 6556    pub async fn open_project_transaction(
 6557        editor: &WeakEntity<Editor>,
 6558        workspace: WeakEntity<Workspace>,
 6559        transaction: ProjectTransaction,
 6560        title: String,
 6561        cx: &mut AsyncWindowContext,
 6562    ) -> Result<()> {
 6563        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6564        cx.update(|_, cx| {
 6565            entries.sort_unstable_by_key(|(buffer, _)| {
 6566                buffer.read(cx).file().map(|f| f.path().clone())
 6567            });
 6568        })?;
 6569        if entries.is_empty() {
 6570            return Ok(());
 6571        }
 6572
 6573        // If the project transaction's edits are all contained within this editor, then
 6574        // avoid opening a new editor to display them.
 6575
 6576        if let [(buffer, transaction)] = &*entries {
 6577            let excerpt = editor.update(cx, |editor, cx| {
 6578                editor
 6579                    .buffer()
 6580                    .read(cx)
 6581                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6582            })?;
 6583            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6584                && excerpted_buffer == *buffer
 6585            {
 6586                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6587                    let excerpt_range = excerpt_range.to_offset(buffer);
 6588                    buffer
 6589                        .edited_ranges_for_transaction::<usize>(transaction)
 6590                        .all(|range| {
 6591                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6592                        })
 6593                })?;
 6594
 6595                if all_edits_within_excerpt {
 6596                    return Ok(());
 6597                }
 6598            }
 6599        }
 6600
 6601        let mut ranges_to_highlight = Vec::new();
 6602        let excerpt_buffer = cx.new(|cx| {
 6603            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6604            for (buffer_handle, transaction) in &entries {
 6605                let edited_ranges = buffer_handle
 6606                    .read(cx)
 6607                    .edited_ranges_for_transaction::<Point>(transaction)
 6608                    .collect::<Vec<_>>();
 6609                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6610                    PathKey::for_buffer(buffer_handle, cx),
 6611                    buffer_handle.clone(),
 6612                    edited_ranges,
 6613                    multibuffer_context_lines(cx),
 6614                    cx,
 6615                );
 6616
 6617                ranges_to_highlight.extend(ranges);
 6618            }
 6619            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6620            multibuffer
 6621        })?;
 6622
 6623        workspace.update_in(cx, |workspace, window, cx| {
 6624            let project = workspace.project().clone();
 6625            let editor =
 6626                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6627            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6628            editor.update(cx, |editor, cx| {
 6629                editor.highlight_background::<Self>(
 6630                    &ranges_to_highlight,
 6631                    |_, theme| theme.colors().editor_highlighted_line_background,
 6632                    cx,
 6633                );
 6634            });
 6635        })?;
 6636
 6637        Ok(())
 6638    }
 6639
 6640    pub fn clear_code_action_providers(&mut self) {
 6641        self.code_action_providers.clear();
 6642        self.available_code_actions.take();
 6643    }
 6644
 6645    pub fn add_code_action_provider(
 6646        &mut self,
 6647        provider: Rc<dyn CodeActionProvider>,
 6648        window: &mut Window,
 6649        cx: &mut Context<Self>,
 6650    ) {
 6651        if self
 6652            .code_action_providers
 6653            .iter()
 6654            .any(|existing_provider| existing_provider.id() == provider.id())
 6655        {
 6656            return;
 6657        }
 6658
 6659        self.code_action_providers.push(provider);
 6660        self.refresh_code_actions(window, cx);
 6661    }
 6662
 6663    pub fn remove_code_action_provider(
 6664        &mut self,
 6665        id: Arc<str>,
 6666        window: &mut Window,
 6667        cx: &mut Context<Self>,
 6668    ) {
 6669        self.code_action_providers
 6670            .retain(|provider| provider.id() != id);
 6671        self.refresh_code_actions(window, cx);
 6672    }
 6673
 6674    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6675        !self.code_action_providers.is_empty()
 6676            && EditorSettings::get_global(cx).toolbar.code_actions
 6677    }
 6678
 6679    pub fn has_available_code_actions(&self) -> bool {
 6680        self.available_code_actions
 6681            .as_ref()
 6682            .is_some_and(|(_, actions)| !actions.is_empty())
 6683    }
 6684
 6685    fn render_inline_code_actions(
 6686        &self,
 6687        icon_size: ui::IconSize,
 6688        display_row: DisplayRow,
 6689        is_active: bool,
 6690        cx: &mut Context<Self>,
 6691    ) -> AnyElement {
 6692        let show_tooltip = !self.context_menu_visible();
 6693        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6694            .icon_size(icon_size)
 6695            .shape(ui::IconButtonShape::Square)
 6696            .icon_color(ui::Color::Hidden)
 6697            .toggle_state(is_active)
 6698            .when(show_tooltip, |this| {
 6699                this.tooltip({
 6700                    let focus_handle = self.focus_handle.clone();
 6701                    move |_window, cx| {
 6702                        Tooltip::for_action_in(
 6703                            "Toggle Code Actions",
 6704                            &ToggleCodeActions {
 6705                                deployed_from: None,
 6706                                quick_launch: false,
 6707                            },
 6708                            &focus_handle,
 6709                            cx,
 6710                        )
 6711                    }
 6712                })
 6713            })
 6714            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6715                window.focus(&editor.focus_handle(cx));
 6716                editor.toggle_code_actions(
 6717                    &crate::actions::ToggleCodeActions {
 6718                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6719                            display_row,
 6720                        )),
 6721                        quick_launch: false,
 6722                    },
 6723                    window,
 6724                    cx,
 6725                );
 6726            }))
 6727            .into_any_element()
 6728    }
 6729
 6730    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6731        &self.context_menu
 6732    }
 6733
 6734    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6735        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6736            cx.background_executor()
 6737                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6738                .await;
 6739
 6740            let (start_buffer, start, _, end, newest_selection) = this
 6741                .update(cx, |this, cx| {
 6742                    let newest_selection = this.selections.newest_anchor().clone();
 6743                    if newest_selection.head().diff_base_anchor.is_some() {
 6744                        return None;
 6745                    }
 6746                    let display_snapshot = this.display_snapshot(cx);
 6747                    let newest_selection_adjusted =
 6748                        this.selections.newest_adjusted(&display_snapshot);
 6749                    let buffer = this.buffer.read(cx);
 6750
 6751                    let (start_buffer, start) =
 6752                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6753                    let (end_buffer, end) =
 6754                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6755
 6756                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6757                })?
 6758                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6759                .context(
 6760                    "Expected selection to lie in a single buffer when refreshing code actions",
 6761                )?;
 6762            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6763                let providers = this.code_action_providers.clone();
 6764                let tasks = this
 6765                    .code_action_providers
 6766                    .iter()
 6767                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6768                    .collect::<Vec<_>>();
 6769                (providers, tasks)
 6770            })?;
 6771
 6772            let mut actions = Vec::new();
 6773            for (provider, provider_actions) in
 6774                providers.into_iter().zip(future::join_all(tasks).await)
 6775            {
 6776                if let Some(provider_actions) = provider_actions.log_err() {
 6777                    actions.extend(provider_actions.into_iter().map(|action| {
 6778                        AvailableCodeAction {
 6779                            excerpt_id: newest_selection.start.excerpt_id,
 6780                            action,
 6781                            provider: provider.clone(),
 6782                        }
 6783                    }));
 6784                }
 6785            }
 6786
 6787            this.update(cx, |this, cx| {
 6788                this.available_code_actions = if actions.is_empty() {
 6789                    None
 6790                } else {
 6791                    Some((
 6792                        Location {
 6793                            buffer: start_buffer,
 6794                            range: start..end,
 6795                        },
 6796                        actions.into(),
 6797                    ))
 6798                };
 6799                cx.notify();
 6800            })
 6801        }));
 6802    }
 6803
 6804    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6805        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6806            self.show_git_blame_inline = false;
 6807
 6808            self.show_git_blame_inline_delay_task =
 6809                Some(cx.spawn_in(window, async move |this, cx| {
 6810                    cx.background_executor().timer(delay).await;
 6811
 6812                    this.update(cx, |this, cx| {
 6813                        this.show_git_blame_inline = true;
 6814                        cx.notify();
 6815                    })
 6816                    .log_err();
 6817                }));
 6818        }
 6819    }
 6820
 6821    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6822        let snapshot = self.snapshot(window, cx);
 6823        let cursor = self
 6824            .selections
 6825            .newest::<Point>(&snapshot.display_snapshot)
 6826            .head();
 6827        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6828        else {
 6829            return;
 6830        };
 6831
 6832        if self.blame.is_none() {
 6833            self.start_git_blame(true, window, cx);
 6834        }
 6835        let Some(blame) = self.blame.as_ref() else {
 6836            return;
 6837        };
 6838
 6839        let row_info = RowInfo {
 6840            buffer_id: Some(buffer.remote_id()),
 6841            buffer_row: Some(point.row),
 6842            ..Default::default()
 6843        };
 6844        let Some((buffer, blame_entry)) = blame
 6845            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6846            .flatten()
 6847        else {
 6848            return;
 6849        };
 6850
 6851        let anchor = self.selections.newest_anchor().head();
 6852        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 6853        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6854            self.show_blame_popover(
 6855                buffer,
 6856                &blame_entry,
 6857                position + last_bounds.origin,
 6858                true,
 6859                cx,
 6860            );
 6861        };
 6862    }
 6863
 6864    fn show_blame_popover(
 6865        &mut self,
 6866        buffer: BufferId,
 6867        blame_entry: &BlameEntry,
 6868        position: gpui::Point<Pixels>,
 6869        ignore_timeout: bool,
 6870        cx: &mut Context<Self>,
 6871    ) {
 6872        if let Some(state) = &mut self.inline_blame_popover {
 6873            state.hide_task.take();
 6874        } else {
 6875            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6876            let blame_entry = blame_entry.clone();
 6877            let show_task = cx.spawn(async move |editor, cx| {
 6878                if !ignore_timeout {
 6879                    cx.background_executor()
 6880                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6881                        .await;
 6882                }
 6883                editor
 6884                    .update(cx, |editor, cx| {
 6885                        editor.inline_blame_popover_show_task.take();
 6886                        let Some(blame) = editor.blame.as_ref() else {
 6887                            return;
 6888                        };
 6889                        let blame = blame.read(cx);
 6890                        let details = blame.details_for_entry(buffer, &blame_entry);
 6891                        let markdown = cx.new(|cx| {
 6892                            Markdown::new(
 6893                                details
 6894                                    .as_ref()
 6895                                    .map(|message| message.message.clone())
 6896                                    .unwrap_or_default(),
 6897                                None,
 6898                                None,
 6899                                cx,
 6900                            )
 6901                        });
 6902                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6903                            position,
 6904                            hide_task: None,
 6905                            popover_bounds: None,
 6906                            popover_state: InlineBlamePopoverState {
 6907                                scroll_handle: ScrollHandle::new(),
 6908                                commit_message: details,
 6909                                markdown,
 6910                            },
 6911                            keyboard_grace: ignore_timeout,
 6912                        });
 6913                        cx.notify();
 6914                    })
 6915                    .ok();
 6916            });
 6917            self.inline_blame_popover_show_task = Some(show_task);
 6918        }
 6919    }
 6920
 6921    pub fn has_mouse_context_menu(&self) -> bool {
 6922        self.mouse_context_menu.is_some()
 6923    }
 6924
 6925    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6926        self.inline_blame_popover_show_task.take();
 6927        if let Some(state) = &mut self.inline_blame_popover {
 6928            let hide_task = cx.spawn(async move |editor, cx| {
 6929                if !ignore_timeout {
 6930                    cx.background_executor()
 6931                        .timer(std::time::Duration::from_millis(100))
 6932                        .await;
 6933                }
 6934                editor
 6935                    .update(cx, |editor, cx| {
 6936                        editor.inline_blame_popover.take();
 6937                        cx.notify();
 6938                    })
 6939                    .ok();
 6940            });
 6941            state.hide_task = Some(hide_task);
 6942            true
 6943        } else {
 6944            false
 6945        }
 6946    }
 6947
 6948    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6949        if self.pending_rename.is_some() {
 6950            return None;
 6951        }
 6952
 6953        let provider = self.semantics_provider.clone()?;
 6954        let buffer = self.buffer.read(cx);
 6955        let newest_selection = self.selections.newest_anchor().clone();
 6956        let cursor_position = newest_selection.head();
 6957        let (cursor_buffer, cursor_buffer_position) =
 6958            buffer.text_anchor_for_position(cursor_position, cx)?;
 6959        let (tail_buffer, tail_buffer_position) =
 6960            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6961        if cursor_buffer != tail_buffer {
 6962            return None;
 6963        }
 6964
 6965        let snapshot = cursor_buffer.read(cx).snapshot();
 6966        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6967        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6968        if start_word_range != end_word_range {
 6969            self.document_highlights_task.take();
 6970            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6971            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6972            return None;
 6973        }
 6974
 6975        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6976        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6977            cx.background_executor()
 6978                .timer(Duration::from_millis(debounce))
 6979                .await;
 6980
 6981            let highlights = if let Some(highlights) = cx
 6982                .update(|cx| {
 6983                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6984                })
 6985                .ok()
 6986                .flatten()
 6987            {
 6988                highlights.await.log_err()
 6989            } else {
 6990                None
 6991            };
 6992
 6993            if let Some(highlights) = highlights {
 6994                this.update(cx, |this, cx| {
 6995                    if this.pending_rename.is_some() {
 6996                        return;
 6997                    }
 6998
 6999                    let buffer = this.buffer.read(cx);
 7000                    if buffer
 7001                        .text_anchor_for_position(cursor_position, cx)
 7002                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7003                    {
 7004                        return;
 7005                    }
 7006
 7007                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7008                    let mut write_ranges = Vec::new();
 7009                    let mut read_ranges = Vec::new();
 7010                    for highlight in highlights {
 7011                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7012                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7013                        {
 7014                            let start = highlight
 7015                                .range
 7016                                .start
 7017                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7018                            let end = highlight
 7019                                .range
 7020                                .end
 7021                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7022                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7023                                continue;
 7024                            }
 7025
 7026                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7027                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7028                                write_ranges.push(range);
 7029                            } else {
 7030                                read_ranges.push(range);
 7031                            }
 7032                        }
 7033                    }
 7034
 7035                    this.highlight_background::<DocumentHighlightRead>(
 7036                        &read_ranges,
 7037                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7038                        cx,
 7039                    );
 7040                    this.highlight_background::<DocumentHighlightWrite>(
 7041                        &write_ranges,
 7042                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7043                        cx,
 7044                    );
 7045                    cx.notify();
 7046                })
 7047                .log_err();
 7048            }
 7049        }));
 7050        None
 7051    }
 7052
 7053    fn prepare_highlight_query_from_selection(
 7054        &mut self,
 7055        window: &Window,
 7056        cx: &mut Context<Editor>,
 7057    ) -> Option<(String, Range<Anchor>)> {
 7058        if matches!(self.mode, EditorMode::SingleLine) {
 7059            return None;
 7060        }
 7061        if !EditorSettings::get_global(cx).selection_highlight {
 7062            return None;
 7063        }
 7064        if self.selections.count() != 1 || self.selections.line_mode() {
 7065            return None;
 7066        }
 7067        let snapshot = self.snapshot(window, cx);
 7068        let selection = self.selections.newest::<Point>(&snapshot);
 7069        // If the selection spans multiple rows OR it is empty
 7070        if selection.start.row != selection.end.row
 7071            || selection.start.column == selection.end.column
 7072        {
 7073            return None;
 7074        }
 7075        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7076        let query = snapshot
 7077            .buffer_snapshot()
 7078            .text_for_range(selection_anchor_range.clone())
 7079            .collect::<String>();
 7080        if query.trim().is_empty() {
 7081            return None;
 7082        }
 7083        Some((query, selection_anchor_range))
 7084    }
 7085
 7086    #[ztracing::instrument(skip_all)]
 7087    fn update_selection_occurrence_highlights(
 7088        &mut self,
 7089        query_text: String,
 7090        query_range: Range<Anchor>,
 7091        multi_buffer_range_to_query: Range<Point>,
 7092        use_debounce: bool,
 7093        window: &mut Window,
 7094        cx: &mut Context<Editor>,
 7095    ) -> Task<()> {
 7096        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7097        cx.spawn_in(window, async move |editor, cx| {
 7098            if use_debounce {
 7099                cx.background_executor()
 7100                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7101                    .await;
 7102            }
 7103            let match_task = cx.background_spawn(async move {
 7104                let buffer_ranges = multi_buffer_snapshot
 7105                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7106                    .into_iter()
 7107                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7108                let mut match_ranges = Vec::new();
 7109                let Ok(regex) = project::search::SearchQuery::text(
 7110                    query_text.clone(),
 7111                    false,
 7112                    false,
 7113                    false,
 7114                    Default::default(),
 7115                    Default::default(),
 7116                    false,
 7117                    None,
 7118                ) else {
 7119                    return Vec::default();
 7120                };
 7121                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7122                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7123                    match_ranges.extend(
 7124                        regex
 7125                            .search(
 7126                                buffer_snapshot,
 7127                                Some(search_range.start.0..search_range.end.0),
 7128                            )
 7129                            .await
 7130                            .into_iter()
 7131                            .filter_map(|match_range| {
 7132                                let match_start = buffer_snapshot
 7133                                    .anchor_after(search_range.start + match_range.start);
 7134                                let match_end = buffer_snapshot
 7135                                    .anchor_before(search_range.start + match_range.end);
 7136                                let match_anchor_range =
 7137                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7138                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7139                            }),
 7140                    );
 7141                }
 7142                match_ranges
 7143            });
 7144            let match_ranges = match_task.await;
 7145            editor
 7146                .update_in(cx, |editor, _, cx| {
 7147                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7148                    if !match_ranges.is_empty() {
 7149                        editor.highlight_background::<SelectedTextHighlight>(
 7150                            &match_ranges,
 7151                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7152                            cx,
 7153                        )
 7154                    }
 7155                })
 7156                .log_err();
 7157        })
 7158    }
 7159
 7160    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7161        struct NewlineFold;
 7162        let type_id = std::any::TypeId::of::<NewlineFold>();
 7163        if !self.mode.is_single_line() {
 7164            return;
 7165        }
 7166        let snapshot = self.snapshot(window, cx);
 7167        if snapshot.buffer_snapshot().max_point().row == 0 {
 7168            return;
 7169        }
 7170        let task = cx.background_spawn(async move {
 7171            let new_newlines = snapshot
 7172                .buffer_chars_at(MultiBufferOffset(0))
 7173                .filter_map(|(c, i)| {
 7174                    if c == '\n' {
 7175                        Some(
 7176                            snapshot.buffer_snapshot().anchor_after(i)
 7177                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7178                        )
 7179                    } else {
 7180                        None
 7181                    }
 7182                })
 7183                .collect::<Vec<_>>();
 7184            let existing_newlines = snapshot
 7185                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7186                .filter_map(|fold| {
 7187                    if fold.placeholder.type_tag == Some(type_id) {
 7188                        Some(fold.range.start..fold.range.end)
 7189                    } else {
 7190                        None
 7191                    }
 7192                })
 7193                .collect::<Vec<_>>();
 7194
 7195            (new_newlines, existing_newlines)
 7196        });
 7197        self.folding_newlines = cx.spawn(async move |this, cx| {
 7198            let (new_newlines, existing_newlines) = task.await;
 7199            if new_newlines == existing_newlines {
 7200                return;
 7201            }
 7202            let placeholder = FoldPlaceholder {
 7203                render: Arc::new(move |_, _, cx| {
 7204                    div()
 7205                        .bg(cx.theme().status().hint_background)
 7206                        .border_b_1()
 7207                        .size_full()
 7208                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7209                        .border_color(cx.theme().status().hint)
 7210                        .child("\\n")
 7211                        .into_any()
 7212                }),
 7213                constrain_width: false,
 7214                merge_adjacent: false,
 7215                type_tag: Some(type_id),
 7216            };
 7217            let creases = new_newlines
 7218                .into_iter()
 7219                .map(|range| Crease::simple(range, placeholder.clone()))
 7220                .collect();
 7221            this.update(cx, |this, cx| {
 7222                this.display_map.update(cx, |display_map, cx| {
 7223                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7224                    display_map.fold(creases, cx);
 7225                });
 7226            })
 7227            .ok();
 7228        });
 7229    }
 7230
 7231    #[ztracing::instrument(skip_all)]
 7232    fn refresh_selected_text_highlights(
 7233        &mut self,
 7234        on_buffer_edit: bool,
 7235        window: &mut Window,
 7236        cx: &mut Context<Editor>,
 7237    ) {
 7238        let Some((query_text, query_range)) =
 7239            self.prepare_highlight_query_from_selection(window, cx)
 7240        else {
 7241            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7242            self.quick_selection_highlight_task.take();
 7243            self.debounced_selection_highlight_task.take();
 7244            return;
 7245        };
 7246        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7247        if on_buffer_edit
 7248            || self
 7249                .quick_selection_highlight_task
 7250                .as_ref()
 7251                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7252        {
 7253            let multi_buffer_visible_start = self
 7254                .scroll_manager
 7255                .anchor()
 7256                .anchor
 7257                .to_point(&multi_buffer_snapshot);
 7258            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7259                multi_buffer_visible_start
 7260                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7261                Bias::Left,
 7262            );
 7263            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7264            self.quick_selection_highlight_task = Some((
 7265                query_range.clone(),
 7266                self.update_selection_occurrence_highlights(
 7267                    query_text.clone(),
 7268                    query_range.clone(),
 7269                    multi_buffer_visible_range,
 7270                    false,
 7271                    window,
 7272                    cx,
 7273                ),
 7274            ));
 7275        }
 7276        if on_buffer_edit
 7277            || self
 7278                .debounced_selection_highlight_task
 7279                .as_ref()
 7280                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7281        {
 7282            let multi_buffer_start = multi_buffer_snapshot
 7283                .anchor_before(MultiBufferOffset(0))
 7284                .to_point(&multi_buffer_snapshot);
 7285            let multi_buffer_end = multi_buffer_snapshot
 7286                .anchor_after(multi_buffer_snapshot.len())
 7287                .to_point(&multi_buffer_snapshot);
 7288            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7289            self.debounced_selection_highlight_task = Some((
 7290                query_range.clone(),
 7291                self.update_selection_occurrence_highlights(
 7292                    query_text,
 7293                    query_range,
 7294                    multi_buffer_full_range,
 7295                    true,
 7296                    window,
 7297                    cx,
 7298                ),
 7299            ));
 7300        }
 7301    }
 7302
 7303    pub fn refresh_edit_prediction(
 7304        &mut self,
 7305        debounce: bool,
 7306        user_requested: bool,
 7307        window: &mut Window,
 7308        cx: &mut Context<Self>,
 7309    ) -> Option<()> {
 7310        if DisableAiSettings::get_global(cx).disable_ai {
 7311            return None;
 7312        }
 7313
 7314        let provider = self.edit_prediction_provider()?;
 7315        let cursor = self.selections.newest_anchor().head();
 7316        let (buffer, cursor_buffer_position) =
 7317            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7318
 7319        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7320            self.discard_edit_prediction(false, cx);
 7321            return None;
 7322        }
 7323
 7324        self.update_visible_edit_prediction(window, cx);
 7325
 7326        if !user_requested
 7327            && (!self.should_show_edit_predictions()
 7328                || !self.is_focused(window)
 7329                || buffer.read(cx).is_empty())
 7330        {
 7331            self.discard_edit_prediction(false, cx);
 7332            return None;
 7333        }
 7334
 7335        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7336        Some(())
 7337    }
 7338
 7339    fn show_edit_predictions_in_menu(&self) -> bool {
 7340        match self.edit_prediction_settings {
 7341            EditPredictionSettings::Disabled => false,
 7342            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7343        }
 7344    }
 7345
 7346    pub fn edit_predictions_enabled(&self) -> bool {
 7347        match self.edit_prediction_settings {
 7348            EditPredictionSettings::Disabled => false,
 7349            EditPredictionSettings::Enabled { .. } => true,
 7350        }
 7351    }
 7352
 7353    fn edit_prediction_requires_modifier(&self) -> bool {
 7354        match self.edit_prediction_settings {
 7355            EditPredictionSettings::Disabled => false,
 7356            EditPredictionSettings::Enabled {
 7357                preview_requires_modifier,
 7358                ..
 7359            } => preview_requires_modifier,
 7360        }
 7361    }
 7362
 7363    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7364        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7365            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7366            self.discard_edit_prediction(false, cx);
 7367        } else {
 7368            let selection = self.selections.newest_anchor();
 7369            let cursor = selection.head();
 7370
 7371            if let Some((buffer, cursor_buffer_position)) =
 7372                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7373            {
 7374                self.edit_prediction_settings =
 7375                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7376            }
 7377        }
 7378    }
 7379
 7380    fn edit_prediction_settings_at_position(
 7381        &self,
 7382        buffer: &Entity<Buffer>,
 7383        buffer_position: language::Anchor,
 7384        cx: &App,
 7385    ) -> EditPredictionSettings {
 7386        if !self.mode.is_full()
 7387            || !self.show_edit_predictions_override.unwrap_or(true)
 7388            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7389        {
 7390            return EditPredictionSettings::Disabled;
 7391        }
 7392
 7393        let buffer = buffer.read(cx);
 7394
 7395        let file = buffer.file();
 7396
 7397        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7398            return EditPredictionSettings::Disabled;
 7399        };
 7400
 7401        let by_provider = matches!(
 7402            self.menu_edit_predictions_policy,
 7403            MenuEditPredictionsPolicy::ByProvider
 7404        );
 7405
 7406        let show_in_menu = by_provider
 7407            && self
 7408                .edit_prediction_provider
 7409                .as_ref()
 7410                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7411
 7412        let preview_requires_modifier =
 7413            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7414
 7415        EditPredictionSettings::Enabled {
 7416            show_in_menu,
 7417            preview_requires_modifier,
 7418        }
 7419    }
 7420
 7421    fn should_show_edit_predictions(&self) -> bool {
 7422        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7423    }
 7424
 7425    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7426        matches!(
 7427            self.edit_prediction_preview,
 7428            EditPredictionPreview::Active { .. }
 7429        )
 7430    }
 7431
 7432    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7433        let cursor = self.selections.newest_anchor().head();
 7434        if let Some((buffer, cursor_position)) =
 7435            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7436        {
 7437            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7438        } else {
 7439            false
 7440        }
 7441    }
 7442
 7443    pub fn supports_minimap(&self, cx: &App) -> bool {
 7444        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7445    }
 7446
 7447    fn edit_predictions_enabled_in_buffer(
 7448        &self,
 7449        buffer: &Entity<Buffer>,
 7450        buffer_position: language::Anchor,
 7451        cx: &App,
 7452    ) -> bool {
 7453        maybe!({
 7454            if self.read_only(cx) {
 7455                return Some(false);
 7456            }
 7457            let provider = self.edit_prediction_provider()?;
 7458            if !provider.is_enabled(buffer, buffer_position, cx) {
 7459                return Some(false);
 7460            }
 7461            let buffer = buffer.read(cx);
 7462            let Some(file) = buffer.file() else {
 7463                return Some(true);
 7464            };
 7465            let settings = all_language_settings(Some(file), cx);
 7466            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7467        })
 7468        .unwrap_or(false)
 7469    }
 7470
 7471    fn cycle_edit_prediction(
 7472        &mut self,
 7473        direction: Direction,
 7474        window: &mut Window,
 7475        cx: &mut Context<Self>,
 7476    ) -> Option<()> {
 7477        let provider = self.edit_prediction_provider()?;
 7478        let cursor = self.selections.newest_anchor().head();
 7479        let (buffer, cursor_buffer_position) =
 7480            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7481        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7482            return None;
 7483        }
 7484
 7485        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7486        self.update_visible_edit_prediction(window, cx);
 7487
 7488        Some(())
 7489    }
 7490
 7491    pub fn show_edit_prediction(
 7492        &mut self,
 7493        _: &ShowEditPrediction,
 7494        window: &mut Window,
 7495        cx: &mut Context<Self>,
 7496    ) {
 7497        if !self.has_active_edit_prediction() {
 7498            self.refresh_edit_prediction(false, true, window, cx);
 7499            return;
 7500        }
 7501
 7502        self.update_visible_edit_prediction(window, cx);
 7503    }
 7504
 7505    pub fn display_cursor_names(
 7506        &mut self,
 7507        _: &DisplayCursorNames,
 7508        window: &mut Window,
 7509        cx: &mut Context<Self>,
 7510    ) {
 7511        self.show_cursor_names(window, cx);
 7512    }
 7513
 7514    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7515        self.show_cursor_names = true;
 7516        cx.notify();
 7517        cx.spawn_in(window, async move |this, cx| {
 7518            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7519            this.update(cx, |this, cx| {
 7520                this.show_cursor_names = false;
 7521                cx.notify()
 7522            })
 7523            .ok()
 7524        })
 7525        .detach();
 7526    }
 7527
 7528    pub fn next_edit_prediction(
 7529        &mut self,
 7530        _: &NextEditPrediction,
 7531        window: &mut Window,
 7532        cx: &mut Context<Self>,
 7533    ) {
 7534        if self.has_active_edit_prediction() {
 7535            self.cycle_edit_prediction(Direction::Next, window, cx);
 7536        } else {
 7537            let is_copilot_disabled = self
 7538                .refresh_edit_prediction(false, true, window, cx)
 7539                .is_none();
 7540            if is_copilot_disabled {
 7541                cx.propagate();
 7542            }
 7543        }
 7544    }
 7545
 7546    pub fn previous_edit_prediction(
 7547        &mut self,
 7548        _: &PreviousEditPrediction,
 7549        window: &mut Window,
 7550        cx: &mut Context<Self>,
 7551    ) {
 7552        if self.has_active_edit_prediction() {
 7553            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7554        } else {
 7555            let is_copilot_disabled = self
 7556                .refresh_edit_prediction(false, true, window, cx)
 7557                .is_none();
 7558            if is_copilot_disabled {
 7559                cx.propagate();
 7560            }
 7561        }
 7562    }
 7563
 7564    pub fn accept_partial_edit_prediction(
 7565        &mut self,
 7566        granularity: EditPredictionGranularity,
 7567        window: &mut Window,
 7568        cx: &mut Context<Self>,
 7569    ) {
 7570        if self.show_edit_predictions_in_menu() {
 7571            self.hide_context_menu(window, cx);
 7572        }
 7573
 7574        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7575            return;
 7576        };
 7577
 7578        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 7579            return;
 7580        }
 7581
 7582        match &active_edit_prediction.completion {
 7583            EditPrediction::MoveWithin { target, .. } => {
 7584                let target = *target;
 7585
 7586                if matches!(granularity, EditPredictionGranularity::Full) {
 7587                    if let Some(position_map) = &self.last_position_map {
 7588                        let target_row = target.to_display_point(&position_map.snapshot).row();
 7589                        let is_visible = position_map.visible_row_range.contains(&target_row);
 7590
 7591                        if is_visible || !self.edit_prediction_requires_modifier() {
 7592                            self.unfold_ranges(&[target..target], true, false, cx);
 7593                            self.change_selections(
 7594                                SelectionEffects::scroll(Autoscroll::newest()),
 7595                                window,
 7596                                cx,
 7597                                |selections| {
 7598                                    selections.select_anchor_ranges([target..target]);
 7599                                },
 7600                            );
 7601                            self.clear_row_highlights::<EditPredictionPreview>();
 7602                            self.edit_prediction_preview
 7603                                .set_previous_scroll_position(None);
 7604                        } else {
 7605                            // Highlight and request scroll
 7606                            self.edit_prediction_preview
 7607                                .set_previous_scroll_position(Some(
 7608                                    position_map.snapshot.scroll_anchor,
 7609                                ));
 7610                            self.highlight_rows::<EditPredictionPreview>(
 7611                                target..target,
 7612                                cx.theme().colors().editor_highlighted_line_background,
 7613                                RowHighlightOptions {
 7614                                    autoscroll: true,
 7615                                    ..Default::default()
 7616                                },
 7617                                cx,
 7618                            );
 7619                            self.request_autoscroll(Autoscroll::fit(), cx);
 7620                        }
 7621                    }
 7622                } else {
 7623                    self.change_selections(
 7624                        SelectionEffects::scroll(Autoscroll::newest()),
 7625                        window,
 7626                        cx,
 7627                        |selections| {
 7628                            selections.select_anchor_ranges([target..target]);
 7629                        },
 7630                    );
 7631                }
 7632            }
 7633            EditPrediction::MoveOutside { snapshot, target } => {
 7634                if let Some(workspace) = self.workspace() {
 7635                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7636                        .detach_and_log_err(cx);
 7637                }
 7638            }
 7639            EditPrediction::Edit { edits, .. } => {
 7640                self.report_edit_prediction_event(
 7641                    active_edit_prediction.completion_id.clone(),
 7642                    true,
 7643                    cx,
 7644                );
 7645
 7646                match granularity {
 7647                    EditPredictionGranularity::Full => {
 7648                        if let Some(provider) = self.edit_prediction_provider() {
 7649                            provider.accept(cx);
 7650                        }
 7651
 7652                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7653                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7654                        let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7655
 7656                        self.buffer.update(cx, |buffer, cx| {
 7657                            buffer.edit(edits.iter().cloned(), None, cx)
 7658                        });
 7659
 7660                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7661                            s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7662                        });
 7663
 7664                        let selections = self.selections.disjoint_anchors_arc();
 7665                        if let Some(transaction_id_now) =
 7666                            self.buffer.read(cx).last_transaction_id(cx)
 7667                        {
 7668                            if transaction_id_prev != Some(transaction_id_now) {
 7669                                self.selection_history
 7670                                    .insert_transaction(transaction_id_now, selections);
 7671                            }
 7672                        }
 7673
 7674                        self.update_visible_edit_prediction(window, cx);
 7675                        if self.active_edit_prediction.is_none() {
 7676                            self.refresh_edit_prediction(true, true, window, cx);
 7677                        }
 7678                        cx.notify();
 7679                    }
 7680                    _ => {
 7681                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7682                        let cursor_offset = self
 7683                            .selections
 7684                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7685                            .head();
 7686
 7687                        let insertion = edits.iter().find_map(|(range, text)| {
 7688                            let range = range.to_offset(&snapshot);
 7689                            if range.is_empty() && range.start == cursor_offset {
 7690                                Some(text)
 7691                            } else {
 7692                                None
 7693                            }
 7694                        });
 7695
 7696                        if let Some(text) = insertion {
 7697                            let text_to_insert = match granularity {
 7698                                EditPredictionGranularity::Word => {
 7699                                    let mut partial = text
 7700                                        .chars()
 7701                                        .by_ref()
 7702                                        .take_while(|c| c.is_alphabetic())
 7703                                        .collect::<String>();
 7704                                    if partial.is_empty() {
 7705                                        partial = text
 7706                                            .chars()
 7707                                            .by_ref()
 7708                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7709                                            .collect::<String>();
 7710                                    }
 7711                                    partial
 7712                                }
 7713                                EditPredictionGranularity::Line => {
 7714                                    if let Some(line) = text.split_inclusive('\n').next() {
 7715                                        line.to_string()
 7716                                    } else {
 7717                                        text.to_string()
 7718                                    }
 7719                                }
 7720                                EditPredictionGranularity::Full => unreachable!(),
 7721                            };
 7722
 7723                            cx.emit(EditorEvent::InputHandled {
 7724                                utf16_range_to_replace: None,
 7725                                text: text_to_insert.clone().into(),
 7726                            });
 7727
 7728                            self.insert_with_autoindent_mode(&text_to_insert, None, window, cx);
 7729                            self.refresh_edit_prediction(true, true, window, cx);
 7730                            cx.notify();
 7731                        } else {
 7732                            self.accept_partial_edit_prediction(
 7733                                EditPredictionGranularity::Full,
 7734                                window,
 7735                                cx,
 7736                            );
 7737                        }
 7738                    }
 7739                }
 7740            }
 7741        }
 7742
 7743        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7744    }
 7745
 7746    pub fn accept_next_word_edit_prediction(
 7747        &mut self,
 7748        _: &AcceptNextWordEditPrediction,
 7749        window: &mut Window,
 7750        cx: &mut Context<Self>,
 7751    ) {
 7752        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 7753    }
 7754
 7755    pub fn accept_next_line_edit_prediction(
 7756        &mut self,
 7757        _: &AcceptNextLineEditPrediction,
 7758        window: &mut Window,
 7759        cx: &mut Context<Self>,
 7760    ) {
 7761        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 7762    }
 7763
 7764    pub fn accept_edit_prediction(
 7765        &mut self,
 7766        _: &AcceptEditPrediction,
 7767        window: &mut Window,
 7768        cx: &mut Context<Self>,
 7769    ) {
 7770        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 7771    }
 7772
 7773    fn discard_edit_prediction(
 7774        &mut self,
 7775        should_report_edit_prediction_event: bool,
 7776        cx: &mut Context<Self>,
 7777    ) -> bool {
 7778        if should_report_edit_prediction_event {
 7779            let completion_id = self
 7780                .active_edit_prediction
 7781                .as_ref()
 7782                .and_then(|active_completion| active_completion.completion_id.clone());
 7783
 7784            self.report_edit_prediction_event(completion_id, false, cx);
 7785        }
 7786
 7787        if let Some(provider) = self.edit_prediction_provider() {
 7788            provider.discard(cx);
 7789        }
 7790
 7791        self.take_active_edit_prediction(cx)
 7792    }
 7793
 7794    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7795        let Some(provider) = self.edit_prediction_provider() else {
 7796            return;
 7797        };
 7798
 7799        let Some((_, buffer, _)) = self
 7800            .buffer
 7801            .read(cx)
 7802            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7803        else {
 7804            return;
 7805        };
 7806
 7807        let extension = buffer
 7808            .read(cx)
 7809            .file()
 7810            .and_then(|file| Some(file.path().extension()?.to_string()));
 7811
 7812        let event_type = match accepted {
 7813            true => "Edit Prediction Accepted",
 7814            false => "Edit Prediction Discarded",
 7815        };
 7816        telemetry::event!(
 7817            event_type,
 7818            provider = provider.name(),
 7819            prediction_id = id,
 7820            suggestion_accepted = accepted,
 7821            file_extension = extension,
 7822        );
 7823    }
 7824
 7825    fn open_editor_at_anchor(
 7826        snapshot: &language::BufferSnapshot,
 7827        target: language::Anchor,
 7828        workspace: &Entity<Workspace>,
 7829        window: &mut Window,
 7830        cx: &mut App,
 7831    ) -> Task<Result<()>> {
 7832        workspace.update(cx, |workspace, cx| {
 7833            let path = snapshot.file().map(|file| file.full_path(cx));
 7834            let Some(path) =
 7835                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7836            else {
 7837                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7838            };
 7839            let target = text::ToPoint::to_point(&target, snapshot);
 7840            let item = workspace.open_path(path, None, true, window, cx);
 7841            window.spawn(cx, async move |cx| {
 7842                let Some(editor) = item.await?.downcast::<Editor>() else {
 7843                    return Ok(());
 7844                };
 7845                editor
 7846                    .update_in(cx, |editor, window, cx| {
 7847                        editor.go_to_singleton_buffer_point(target, window, cx);
 7848                    })
 7849                    .ok();
 7850                anyhow::Ok(())
 7851            })
 7852        })
 7853    }
 7854
 7855    pub fn has_active_edit_prediction(&self) -> bool {
 7856        self.active_edit_prediction.is_some()
 7857    }
 7858
 7859    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7860        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7861            return false;
 7862        };
 7863
 7864        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7865        self.clear_highlights::<EditPredictionHighlight>(cx);
 7866        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7867        true
 7868    }
 7869
 7870    /// Returns true when we're displaying the edit prediction popover below the cursor
 7871    /// like we are not previewing and the LSP autocomplete menu is visible
 7872    /// or we are in `when_holding_modifier` mode.
 7873    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7874        if self.edit_prediction_preview_is_active()
 7875            || !self.show_edit_predictions_in_menu()
 7876            || !self.edit_predictions_enabled()
 7877        {
 7878            return false;
 7879        }
 7880
 7881        if self.has_visible_completions_menu() {
 7882            return true;
 7883        }
 7884
 7885        has_completion && self.edit_prediction_requires_modifier()
 7886    }
 7887
 7888    fn handle_modifiers_changed(
 7889        &mut self,
 7890        modifiers: Modifiers,
 7891        position_map: &PositionMap,
 7892        window: &mut Window,
 7893        cx: &mut Context<Self>,
 7894    ) {
 7895        // Ensure that the edit prediction preview is updated, even when not
 7896        // enabled, if there's an active edit prediction preview.
 7897        if self.show_edit_predictions_in_menu()
 7898            || matches!(
 7899                self.edit_prediction_preview,
 7900                EditPredictionPreview::Active { .. }
 7901            )
 7902        {
 7903            self.update_edit_prediction_preview(&modifiers, window, cx);
 7904        }
 7905
 7906        self.update_selection_mode(&modifiers, position_map, window, cx);
 7907
 7908        let mouse_position = window.mouse_position();
 7909        if !position_map.text_hitbox.is_hovered(window) {
 7910            return;
 7911        }
 7912
 7913        self.update_hovered_link(
 7914            position_map.point_for_position(mouse_position),
 7915            &position_map.snapshot,
 7916            modifiers,
 7917            window,
 7918            cx,
 7919        )
 7920    }
 7921
 7922    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7923        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7924            MultiCursorModifier::Alt => modifiers.secondary(),
 7925            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7926        }
 7927    }
 7928
 7929    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7930        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7931            MultiCursorModifier::Alt => modifiers.alt,
 7932            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7933        }
 7934    }
 7935
 7936    fn columnar_selection_mode(
 7937        modifiers: &Modifiers,
 7938        cx: &mut Context<Self>,
 7939    ) -> Option<ColumnarMode> {
 7940        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7941            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7942                Some(ColumnarMode::FromMouse)
 7943            } else if Self::is_alt_pressed(modifiers, cx) {
 7944                Some(ColumnarMode::FromSelection)
 7945            } else {
 7946                None
 7947            }
 7948        } else {
 7949            None
 7950        }
 7951    }
 7952
 7953    fn update_selection_mode(
 7954        &mut self,
 7955        modifiers: &Modifiers,
 7956        position_map: &PositionMap,
 7957        window: &mut Window,
 7958        cx: &mut Context<Self>,
 7959    ) {
 7960        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7961            return;
 7962        };
 7963        if self.selections.pending_anchor().is_none() {
 7964            return;
 7965        }
 7966
 7967        let mouse_position = window.mouse_position();
 7968        let point_for_position = position_map.point_for_position(mouse_position);
 7969        let position = point_for_position.previous_valid;
 7970
 7971        self.select(
 7972            SelectPhase::BeginColumnar {
 7973                position,
 7974                reset: false,
 7975                mode,
 7976                goal_column: point_for_position.exact_unclipped.column(),
 7977            },
 7978            window,
 7979            cx,
 7980        );
 7981    }
 7982
 7983    fn update_edit_prediction_preview(
 7984        &mut self,
 7985        modifiers: &Modifiers,
 7986        window: &mut Window,
 7987        cx: &mut Context<Self>,
 7988    ) {
 7989        let mut modifiers_held = false;
 7990
 7991        // Check bindings for all granularities.
 7992        // If the user holds the key for Word, Line, or Full, we want to show the preview.
 7993        let granularities = [
 7994            EditPredictionGranularity::Full,
 7995            EditPredictionGranularity::Line,
 7996            EditPredictionGranularity::Word,
 7997        ];
 7998
 7999        for granularity in granularities {
 8000            if let Some(keystroke) = self
 8001                .accept_edit_prediction_keybind(granularity, window, cx)
 8002                .keystroke()
 8003            {
 8004                modifiers_held = modifiers_held
 8005                    || (keystroke.modifiers() == modifiers && keystroke.modifiers().modified());
 8006            }
 8007        }
 8008
 8009        if modifiers_held {
 8010            if matches!(
 8011                self.edit_prediction_preview,
 8012                EditPredictionPreview::Inactive { .. }
 8013            ) {
 8014                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 8015                    provider.provider.did_show(cx)
 8016                }
 8017
 8018                self.edit_prediction_preview = EditPredictionPreview::Active {
 8019                    previous_scroll_position: None,
 8020                    since: Instant::now(),
 8021                };
 8022
 8023                self.update_visible_edit_prediction(window, cx);
 8024                cx.notify();
 8025            }
 8026        } else if let EditPredictionPreview::Active {
 8027            previous_scroll_position,
 8028            since,
 8029        } = self.edit_prediction_preview
 8030        {
 8031            if let (Some(previous_scroll_position), Some(position_map)) =
 8032                (previous_scroll_position, self.last_position_map.as_ref())
 8033            {
 8034                self.set_scroll_position(
 8035                    previous_scroll_position
 8036                        .scroll_position(&position_map.snapshot.display_snapshot),
 8037                    window,
 8038                    cx,
 8039                );
 8040            }
 8041
 8042            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8043                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8044            };
 8045            self.clear_row_highlights::<EditPredictionPreview>();
 8046            self.update_visible_edit_prediction(window, cx);
 8047            cx.notify();
 8048        }
 8049    }
 8050
 8051    fn update_visible_edit_prediction(
 8052        &mut self,
 8053        _window: &mut Window,
 8054        cx: &mut Context<Self>,
 8055    ) -> Option<()> {
 8056        if DisableAiSettings::get_global(cx).disable_ai {
 8057            return None;
 8058        }
 8059
 8060        if self.ime_transaction.is_some() {
 8061            self.discard_edit_prediction(false, cx);
 8062            return None;
 8063        }
 8064
 8065        let selection = self.selections.newest_anchor();
 8066        let cursor = selection.head();
 8067        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8068        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8069        let excerpt_id = cursor.excerpt_id;
 8070
 8071        let show_in_menu = self.show_edit_predictions_in_menu();
 8072        let completions_menu_has_precedence = !show_in_menu
 8073            && (self.context_menu.borrow().is_some()
 8074                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8075
 8076        if completions_menu_has_precedence
 8077            || !offset_selection.is_empty()
 8078            || self
 8079                .active_edit_prediction
 8080                .as_ref()
 8081                .is_some_and(|completion| {
 8082                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8083                        return false;
 8084                    };
 8085                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8086                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8087                    !invalidation_range.contains(&offset_selection.head())
 8088                })
 8089        {
 8090            self.discard_edit_prediction(false, cx);
 8091            return None;
 8092        }
 8093
 8094        self.take_active_edit_prediction(cx);
 8095        let Some(provider) = self.edit_prediction_provider() else {
 8096            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8097            return None;
 8098        };
 8099
 8100        let (buffer, cursor_buffer_position) =
 8101            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8102
 8103        self.edit_prediction_settings =
 8104            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8105
 8106        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8107
 8108        if self.edit_prediction_indent_conflict {
 8109            let cursor_point = cursor.to_point(&multibuffer);
 8110            let mut suggested_indent = None;
 8111            multibuffer.suggested_indents_callback(
 8112                cursor_point.row..cursor_point.row + 1,
 8113                |_, indent| {
 8114                    suggested_indent = Some(indent);
 8115                    ControlFlow::Break(())
 8116                },
 8117                cx,
 8118            );
 8119
 8120            if let Some(indent) = suggested_indent
 8121                && indent.len == cursor_point.column
 8122            {
 8123                self.edit_prediction_indent_conflict = false;
 8124            }
 8125        }
 8126
 8127        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8128
 8129        let (completion_id, edits, edit_preview) = match edit_prediction {
 8130            edit_prediction_types::EditPrediction::Local {
 8131                id,
 8132                edits,
 8133                edit_preview,
 8134            } => (id, edits, edit_preview),
 8135            edit_prediction_types::EditPrediction::Jump {
 8136                id,
 8137                snapshot,
 8138                target,
 8139            } => {
 8140                self.stale_edit_prediction_in_menu = None;
 8141                self.active_edit_prediction = Some(EditPredictionState {
 8142                    inlay_ids: vec![],
 8143                    completion: EditPrediction::MoveOutside { snapshot, target },
 8144                    completion_id: id,
 8145                    invalidation_range: None,
 8146                });
 8147                cx.notify();
 8148                return Some(());
 8149            }
 8150        };
 8151
 8152        let edits = edits
 8153            .into_iter()
 8154            .flat_map(|(range, new_text)| {
 8155                Some((
 8156                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8157                    new_text,
 8158                ))
 8159            })
 8160            .collect::<Vec<_>>();
 8161        if edits.is_empty() {
 8162            return None;
 8163        }
 8164
 8165        let first_edit_start = edits.first().unwrap().0.start;
 8166        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8167        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8168
 8169        let last_edit_end = edits.last().unwrap().0.end;
 8170        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8171        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8172
 8173        let cursor_row = cursor.to_point(&multibuffer).row;
 8174
 8175        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8176
 8177        let mut inlay_ids = Vec::new();
 8178        let invalidation_row_range;
 8179        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8180            Some(cursor_row..edit_end_row)
 8181        } else if cursor_row > edit_end_row {
 8182            Some(edit_start_row..cursor_row)
 8183        } else {
 8184            None
 8185        };
 8186        let supports_jump = self
 8187            .edit_prediction_provider
 8188            .as_ref()
 8189            .map(|provider| provider.provider.supports_jump_to_edit())
 8190            .unwrap_or(true);
 8191
 8192        let is_move = supports_jump
 8193            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8194        let completion = if is_move {
 8195            invalidation_row_range =
 8196                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8197            let target = first_edit_start;
 8198            EditPrediction::MoveWithin { target, snapshot }
 8199        } else {
 8200            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8201                && !self.edit_predictions_hidden_for_vim_mode;
 8202
 8203            if show_completions_in_buffer {
 8204                if let Some(provider) = &self.edit_prediction_provider {
 8205                    provider.provider.did_show(cx);
 8206                }
 8207                if edits
 8208                    .iter()
 8209                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8210                {
 8211                    let mut inlays = Vec::new();
 8212                    for (range, new_text) in &edits {
 8213                        let inlay = Inlay::edit_prediction(
 8214                            post_inc(&mut self.next_inlay_id),
 8215                            range.start,
 8216                            new_text.as_ref(),
 8217                        );
 8218                        inlay_ids.push(inlay.id);
 8219                        inlays.push(inlay);
 8220                    }
 8221
 8222                    self.splice_inlays(&[], inlays, cx);
 8223                } else {
 8224                    let background_color = cx.theme().status().deleted_background;
 8225                    self.highlight_text::<EditPredictionHighlight>(
 8226                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8227                        HighlightStyle {
 8228                            background_color: Some(background_color),
 8229                            ..Default::default()
 8230                        },
 8231                        cx,
 8232                    );
 8233                }
 8234            }
 8235
 8236            invalidation_row_range = edit_start_row..edit_end_row;
 8237
 8238            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8239                if provider.show_tab_accept_marker() {
 8240                    EditDisplayMode::TabAccept
 8241                } else {
 8242                    EditDisplayMode::Inline
 8243                }
 8244            } else {
 8245                EditDisplayMode::DiffPopover
 8246            };
 8247
 8248            EditPrediction::Edit {
 8249                edits,
 8250                edit_preview,
 8251                display_mode,
 8252                snapshot,
 8253            }
 8254        };
 8255
 8256        let invalidation_range = multibuffer
 8257            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8258            ..multibuffer.anchor_after(Point::new(
 8259                invalidation_row_range.end,
 8260                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8261            ));
 8262
 8263        self.stale_edit_prediction_in_menu = None;
 8264        self.active_edit_prediction = Some(EditPredictionState {
 8265            inlay_ids,
 8266            completion,
 8267            completion_id,
 8268            invalidation_range: Some(invalidation_range),
 8269        });
 8270
 8271        cx.notify();
 8272
 8273        Some(())
 8274    }
 8275
 8276    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8277        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8278    }
 8279
 8280    fn clear_tasks(&mut self) {
 8281        self.tasks.clear()
 8282    }
 8283
 8284    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8285        if self.tasks.insert(key, value).is_some() {
 8286            // This case should hopefully be rare, but just in case...
 8287            log::error!(
 8288                "multiple different run targets found on a single line, only the last target will be rendered"
 8289            )
 8290        }
 8291    }
 8292
 8293    /// Get all display points of breakpoints that will be rendered within editor
 8294    ///
 8295    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8296    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8297    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8298    fn active_breakpoints(
 8299        &self,
 8300        range: Range<DisplayRow>,
 8301        window: &mut Window,
 8302        cx: &mut Context<Self>,
 8303    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8304        let mut breakpoint_display_points = HashMap::default();
 8305
 8306        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8307            return breakpoint_display_points;
 8308        };
 8309
 8310        let snapshot = self.snapshot(window, cx);
 8311
 8312        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8313        let Some(project) = self.project() else {
 8314            return breakpoint_display_points;
 8315        };
 8316
 8317        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8318            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8319
 8320        for (buffer_snapshot, range, excerpt_id) in
 8321            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8322        {
 8323            let Some(buffer) = project
 8324                .read(cx)
 8325                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8326            else {
 8327                continue;
 8328            };
 8329            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8330                &buffer,
 8331                Some(
 8332                    buffer_snapshot.anchor_before(range.start)
 8333                        ..buffer_snapshot.anchor_after(range.end),
 8334                ),
 8335                buffer_snapshot,
 8336                cx,
 8337            );
 8338            for (breakpoint, state) in breakpoints {
 8339                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8340                let position = multi_buffer_anchor
 8341                    .to_point(&multi_buffer_snapshot)
 8342                    .to_display_point(&snapshot);
 8343
 8344                breakpoint_display_points.insert(
 8345                    position.row(),
 8346                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8347                );
 8348            }
 8349        }
 8350
 8351        breakpoint_display_points
 8352    }
 8353
 8354    fn breakpoint_context_menu(
 8355        &self,
 8356        anchor: Anchor,
 8357        window: &mut Window,
 8358        cx: &mut Context<Self>,
 8359    ) -> Entity<ui::ContextMenu> {
 8360        let weak_editor = cx.weak_entity();
 8361        let focus_handle = self.focus_handle(cx);
 8362
 8363        let row = self
 8364            .buffer
 8365            .read(cx)
 8366            .snapshot(cx)
 8367            .summary_for_anchor::<Point>(&anchor)
 8368            .row;
 8369
 8370        let breakpoint = self
 8371            .breakpoint_at_row(row, window, cx)
 8372            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8373
 8374        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8375            "Edit Log Breakpoint"
 8376        } else {
 8377            "Set Log Breakpoint"
 8378        };
 8379
 8380        let condition_breakpoint_msg = if breakpoint
 8381            .as_ref()
 8382            .is_some_and(|bp| bp.1.condition.is_some())
 8383        {
 8384            "Edit Condition Breakpoint"
 8385        } else {
 8386            "Set Condition Breakpoint"
 8387        };
 8388
 8389        let hit_condition_breakpoint_msg = if breakpoint
 8390            .as_ref()
 8391            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8392        {
 8393            "Edit Hit Condition Breakpoint"
 8394        } else {
 8395            "Set Hit Condition Breakpoint"
 8396        };
 8397
 8398        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8399            "Unset Breakpoint"
 8400        } else {
 8401            "Set Breakpoint"
 8402        };
 8403
 8404        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8405
 8406        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8407            BreakpointState::Enabled => Some("Disable"),
 8408            BreakpointState::Disabled => Some("Enable"),
 8409        });
 8410
 8411        let (anchor, breakpoint) =
 8412            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8413
 8414        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8415            menu.on_blur_subscription(Subscription::new(|| {}))
 8416                .context(focus_handle)
 8417                .when(run_to_cursor, |this| {
 8418                    let weak_editor = weak_editor.clone();
 8419                    this.entry("Run to cursor", None, move |window, cx| {
 8420                        weak_editor
 8421                            .update(cx, |editor, cx| {
 8422                                editor.change_selections(
 8423                                    SelectionEffects::no_scroll(),
 8424                                    window,
 8425                                    cx,
 8426                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8427                                );
 8428                            })
 8429                            .ok();
 8430
 8431                        window.dispatch_action(Box::new(RunToCursor), cx);
 8432                    })
 8433                    .separator()
 8434                })
 8435                .when_some(toggle_state_msg, |this, msg| {
 8436                    this.entry(msg, None, {
 8437                        let weak_editor = weak_editor.clone();
 8438                        let breakpoint = breakpoint.clone();
 8439                        move |_window, cx| {
 8440                            weak_editor
 8441                                .update(cx, |this, cx| {
 8442                                    this.edit_breakpoint_at_anchor(
 8443                                        anchor,
 8444                                        breakpoint.as_ref().clone(),
 8445                                        BreakpointEditAction::InvertState,
 8446                                        cx,
 8447                                    );
 8448                                })
 8449                                .log_err();
 8450                        }
 8451                    })
 8452                })
 8453                .entry(set_breakpoint_msg, None, {
 8454                    let weak_editor = weak_editor.clone();
 8455                    let breakpoint = breakpoint.clone();
 8456                    move |_window, cx| {
 8457                        weak_editor
 8458                            .update(cx, |this, cx| {
 8459                                this.edit_breakpoint_at_anchor(
 8460                                    anchor,
 8461                                    breakpoint.as_ref().clone(),
 8462                                    BreakpointEditAction::Toggle,
 8463                                    cx,
 8464                                );
 8465                            })
 8466                            .log_err();
 8467                    }
 8468                })
 8469                .entry(log_breakpoint_msg, None, {
 8470                    let breakpoint = breakpoint.clone();
 8471                    let weak_editor = weak_editor.clone();
 8472                    move |window, cx| {
 8473                        weak_editor
 8474                            .update(cx, |this, cx| {
 8475                                this.add_edit_breakpoint_block(
 8476                                    anchor,
 8477                                    breakpoint.as_ref(),
 8478                                    BreakpointPromptEditAction::Log,
 8479                                    window,
 8480                                    cx,
 8481                                );
 8482                            })
 8483                            .log_err();
 8484                    }
 8485                })
 8486                .entry(condition_breakpoint_msg, None, {
 8487                    let breakpoint = breakpoint.clone();
 8488                    let weak_editor = weak_editor.clone();
 8489                    move |window, cx| {
 8490                        weak_editor
 8491                            .update(cx, |this, cx| {
 8492                                this.add_edit_breakpoint_block(
 8493                                    anchor,
 8494                                    breakpoint.as_ref(),
 8495                                    BreakpointPromptEditAction::Condition,
 8496                                    window,
 8497                                    cx,
 8498                                );
 8499                            })
 8500                            .log_err();
 8501                    }
 8502                })
 8503                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8504                    weak_editor
 8505                        .update(cx, |this, cx| {
 8506                            this.add_edit_breakpoint_block(
 8507                                anchor,
 8508                                breakpoint.as_ref(),
 8509                                BreakpointPromptEditAction::HitCondition,
 8510                                window,
 8511                                cx,
 8512                            );
 8513                        })
 8514                        .log_err();
 8515                })
 8516        })
 8517    }
 8518
 8519    fn render_breakpoint(
 8520        &self,
 8521        position: Anchor,
 8522        row: DisplayRow,
 8523        breakpoint: &Breakpoint,
 8524        state: Option<BreakpointSessionState>,
 8525        cx: &mut Context<Self>,
 8526    ) -> IconButton {
 8527        let is_rejected = state.is_some_and(|s| !s.verified);
 8528        // Is it a breakpoint that shows up when hovering over gutter?
 8529        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8530            (false, false),
 8531            |PhantomBreakpointIndicator {
 8532                 is_active,
 8533                 display_row,
 8534                 collides_with_existing_breakpoint,
 8535             }| {
 8536                (
 8537                    is_active && display_row == row,
 8538                    collides_with_existing_breakpoint,
 8539                )
 8540            },
 8541        );
 8542
 8543        let (color, icon) = {
 8544            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8545                (false, false) => ui::IconName::DebugBreakpoint,
 8546                (true, false) => ui::IconName::DebugLogBreakpoint,
 8547                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8548                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8549            };
 8550
 8551            let color = cx.theme().colors();
 8552
 8553            let color = if is_phantom {
 8554                if collides_with_existing {
 8555                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8556                } else {
 8557                    Color::Hint
 8558                }
 8559            } else if is_rejected {
 8560                Color::Disabled
 8561            } else {
 8562                Color::Debugger
 8563            };
 8564
 8565            (color, icon)
 8566        };
 8567
 8568        let breakpoint = Arc::from(breakpoint.clone());
 8569
 8570        let alt_as_text = gpui::Keystroke {
 8571            modifiers: Modifiers::secondary_key(),
 8572            ..Default::default()
 8573        };
 8574        let primary_action_text = if breakpoint.is_disabled() {
 8575            "Enable breakpoint"
 8576        } else if is_phantom && !collides_with_existing {
 8577            "Set breakpoint"
 8578        } else {
 8579            "Unset breakpoint"
 8580        };
 8581        let focus_handle = self.focus_handle.clone();
 8582
 8583        let meta = if is_rejected {
 8584            SharedString::from("No executable code is associated with this line.")
 8585        } else if collides_with_existing && !breakpoint.is_disabled() {
 8586            SharedString::from(format!(
 8587                "{alt_as_text}-click to disable,\nright-click for more options."
 8588            ))
 8589        } else {
 8590            SharedString::from("Right-click for more options.")
 8591        };
 8592        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8593            .icon_size(IconSize::XSmall)
 8594            .size(ui::ButtonSize::None)
 8595            .when(is_rejected, |this| {
 8596                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8597            })
 8598            .icon_color(color)
 8599            .style(ButtonStyle::Transparent)
 8600            .on_click(cx.listener({
 8601                move |editor, event: &ClickEvent, window, cx| {
 8602                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8603                        BreakpointEditAction::InvertState
 8604                    } else {
 8605                        BreakpointEditAction::Toggle
 8606                    };
 8607
 8608                    window.focus(&editor.focus_handle(cx));
 8609                    editor.edit_breakpoint_at_anchor(
 8610                        position,
 8611                        breakpoint.as_ref().clone(),
 8612                        edit_action,
 8613                        cx,
 8614                    );
 8615                }
 8616            }))
 8617            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8618                editor.set_breakpoint_context_menu(
 8619                    row,
 8620                    Some(position),
 8621                    event.position(),
 8622                    window,
 8623                    cx,
 8624                );
 8625            }))
 8626            .tooltip(move |_window, cx| {
 8627                Tooltip::with_meta_in(
 8628                    primary_action_text,
 8629                    Some(&ToggleBreakpoint),
 8630                    meta.clone(),
 8631                    &focus_handle,
 8632                    cx,
 8633                )
 8634            })
 8635    }
 8636
 8637    fn build_tasks_context(
 8638        project: &Entity<Project>,
 8639        buffer: &Entity<Buffer>,
 8640        buffer_row: u32,
 8641        tasks: &Arc<RunnableTasks>,
 8642        cx: &mut Context<Self>,
 8643    ) -> Task<Option<task::TaskContext>> {
 8644        let position = Point::new(buffer_row, tasks.column);
 8645        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8646        let location = Location {
 8647            buffer: buffer.clone(),
 8648            range: range_start..range_start,
 8649        };
 8650        // Fill in the environmental variables from the tree-sitter captures
 8651        let mut captured_task_variables = TaskVariables::default();
 8652        for (capture_name, value) in tasks.extra_variables.clone() {
 8653            captured_task_variables.insert(
 8654                task::VariableName::Custom(capture_name.into()),
 8655                value.clone(),
 8656            );
 8657        }
 8658        project.update(cx, |project, cx| {
 8659            project.task_store().update(cx, |task_store, cx| {
 8660                task_store.task_context_for_location(captured_task_variables, location, cx)
 8661            })
 8662        })
 8663    }
 8664
 8665    pub fn spawn_nearest_task(
 8666        &mut self,
 8667        action: &SpawnNearestTask,
 8668        window: &mut Window,
 8669        cx: &mut Context<Self>,
 8670    ) {
 8671        let Some((workspace, _)) = self.workspace.clone() else {
 8672            return;
 8673        };
 8674        let Some(project) = self.project.clone() else {
 8675            return;
 8676        };
 8677
 8678        // Try to find a closest, enclosing node using tree-sitter that has a task
 8679        let Some((buffer, buffer_row, tasks)) = self
 8680            .find_enclosing_node_task(cx)
 8681            // Or find the task that's closest in row-distance.
 8682            .or_else(|| self.find_closest_task(cx))
 8683        else {
 8684            return;
 8685        };
 8686
 8687        let reveal_strategy = action.reveal;
 8688        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8689        cx.spawn_in(window, async move |_, cx| {
 8690            let context = task_context.await?;
 8691            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8692
 8693            let resolved = &mut resolved_task.resolved;
 8694            resolved.reveal = reveal_strategy;
 8695
 8696            workspace
 8697                .update_in(cx, |workspace, window, cx| {
 8698                    workspace.schedule_resolved_task(
 8699                        task_source_kind,
 8700                        resolved_task,
 8701                        false,
 8702                        window,
 8703                        cx,
 8704                    );
 8705                })
 8706                .ok()
 8707        })
 8708        .detach();
 8709    }
 8710
 8711    fn find_closest_task(
 8712        &mut self,
 8713        cx: &mut Context<Self>,
 8714    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8715        let cursor_row = self
 8716            .selections
 8717            .newest_adjusted(&self.display_snapshot(cx))
 8718            .head()
 8719            .row;
 8720
 8721        let ((buffer_id, row), tasks) = self
 8722            .tasks
 8723            .iter()
 8724            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8725
 8726        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8727        let tasks = Arc::new(tasks.to_owned());
 8728        Some((buffer, *row, tasks))
 8729    }
 8730
 8731    fn find_enclosing_node_task(
 8732        &mut self,
 8733        cx: &mut Context<Self>,
 8734    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8735        let snapshot = self.buffer.read(cx).snapshot(cx);
 8736        let offset = self
 8737            .selections
 8738            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8739            .head();
 8740        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8741        let offset = excerpt.map_offset_to_buffer(offset);
 8742        let buffer_id = excerpt.buffer().remote_id();
 8743
 8744        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8745        let mut cursor = layer.node().walk();
 8746
 8747        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8748            if cursor.node().end_byte() == offset.0 {
 8749                cursor.goto_next_sibling();
 8750            }
 8751        }
 8752
 8753        // Ascend to the smallest ancestor that contains the range and has a task.
 8754        loop {
 8755            let node = cursor.node();
 8756            let node_range = node.byte_range();
 8757            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8758
 8759            // Check if this node contains our offset
 8760            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8761                // If it contains offset, check for task
 8762                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8763                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8764                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8765                }
 8766            }
 8767
 8768            if !cursor.goto_parent() {
 8769                break;
 8770            }
 8771        }
 8772        None
 8773    }
 8774
 8775    fn render_run_indicator(
 8776        &self,
 8777        _style: &EditorStyle,
 8778        is_active: bool,
 8779        row: DisplayRow,
 8780        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8781        cx: &mut Context<Self>,
 8782    ) -> IconButton {
 8783        let color = Color::Muted;
 8784        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8785
 8786        IconButton::new(
 8787            ("run_indicator", row.0 as usize),
 8788            ui::IconName::PlayOutlined,
 8789        )
 8790        .shape(ui::IconButtonShape::Square)
 8791        .icon_size(IconSize::XSmall)
 8792        .icon_color(color)
 8793        .toggle_state(is_active)
 8794        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8795            let quick_launch = match e {
 8796                ClickEvent::Keyboard(_) => true,
 8797                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8798            };
 8799
 8800            window.focus(&editor.focus_handle(cx));
 8801            editor.toggle_code_actions(
 8802                &ToggleCodeActions {
 8803                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8804                    quick_launch,
 8805                },
 8806                window,
 8807                cx,
 8808            );
 8809        }))
 8810        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8811            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8812        }))
 8813    }
 8814
 8815    pub fn context_menu_visible(&self) -> bool {
 8816        !self.edit_prediction_preview_is_active()
 8817            && self
 8818                .context_menu
 8819                .borrow()
 8820                .as_ref()
 8821                .is_some_and(|menu| menu.visible())
 8822    }
 8823
 8824    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8825        self.context_menu
 8826            .borrow()
 8827            .as_ref()
 8828            .map(|menu| menu.origin())
 8829    }
 8830
 8831    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8832        self.context_menu_options = Some(options);
 8833    }
 8834
 8835    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8836    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8837
 8838    fn render_edit_prediction_popover(
 8839        &mut self,
 8840        text_bounds: &Bounds<Pixels>,
 8841        content_origin: gpui::Point<Pixels>,
 8842        right_margin: Pixels,
 8843        editor_snapshot: &EditorSnapshot,
 8844        visible_row_range: Range<DisplayRow>,
 8845        scroll_top: ScrollOffset,
 8846        scroll_bottom: ScrollOffset,
 8847        line_layouts: &[LineWithInvisibles],
 8848        line_height: Pixels,
 8849        scroll_position: gpui::Point<ScrollOffset>,
 8850        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8851        newest_selection_head: Option<DisplayPoint>,
 8852        editor_width: Pixels,
 8853        style: &EditorStyle,
 8854        window: &mut Window,
 8855        cx: &mut App,
 8856    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8857        if self.mode().is_minimap() {
 8858            return None;
 8859        }
 8860        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8861
 8862        if self.edit_prediction_visible_in_cursor_popover(true) {
 8863            return None;
 8864        }
 8865
 8866        match &active_edit_prediction.completion {
 8867            EditPrediction::MoveWithin { target, .. } => {
 8868                let target_display_point = target.to_display_point(editor_snapshot);
 8869
 8870                if self.edit_prediction_requires_modifier() {
 8871                    if !self.edit_prediction_preview_is_active() {
 8872                        return None;
 8873                    }
 8874
 8875                    self.render_edit_prediction_modifier_jump_popover(
 8876                        text_bounds,
 8877                        content_origin,
 8878                        visible_row_range,
 8879                        line_layouts,
 8880                        line_height,
 8881                        scroll_pixel_position,
 8882                        newest_selection_head,
 8883                        target_display_point,
 8884                        window,
 8885                        cx,
 8886                    )
 8887                } else {
 8888                    self.render_edit_prediction_eager_jump_popover(
 8889                        text_bounds,
 8890                        content_origin,
 8891                        editor_snapshot,
 8892                        visible_row_range,
 8893                        scroll_top,
 8894                        scroll_bottom,
 8895                        line_height,
 8896                        scroll_pixel_position,
 8897                        target_display_point,
 8898                        editor_width,
 8899                        window,
 8900                        cx,
 8901                    )
 8902                }
 8903            }
 8904            EditPrediction::Edit {
 8905                display_mode: EditDisplayMode::Inline,
 8906                ..
 8907            } => None,
 8908            EditPrediction::Edit {
 8909                display_mode: EditDisplayMode::TabAccept,
 8910                edits,
 8911                ..
 8912            } => {
 8913                let range = &edits.first()?.0;
 8914                let target_display_point = range.end.to_display_point(editor_snapshot);
 8915
 8916                self.render_edit_prediction_end_of_line_popover(
 8917                    "Accept",
 8918                    editor_snapshot,
 8919                    visible_row_range,
 8920                    target_display_point,
 8921                    line_height,
 8922                    scroll_pixel_position,
 8923                    content_origin,
 8924                    editor_width,
 8925                    window,
 8926                    cx,
 8927                )
 8928            }
 8929            EditPrediction::Edit {
 8930                edits,
 8931                edit_preview,
 8932                display_mode: EditDisplayMode::DiffPopover,
 8933                snapshot,
 8934            } => self.render_edit_prediction_diff_popover(
 8935                text_bounds,
 8936                content_origin,
 8937                right_margin,
 8938                editor_snapshot,
 8939                visible_row_range,
 8940                line_layouts,
 8941                line_height,
 8942                scroll_position,
 8943                scroll_pixel_position,
 8944                newest_selection_head,
 8945                editor_width,
 8946                style,
 8947                edits,
 8948                edit_preview,
 8949                snapshot,
 8950                window,
 8951                cx,
 8952            ),
 8953            EditPrediction::MoveOutside { snapshot, .. } => {
 8954                let mut element = self
 8955                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 8956                    .into_any();
 8957
 8958                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8959                let origin_x = text_bounds.size.width - size.width - px(30.);
 8960                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 8961                element.prepaint_at(origin, window, cx);
 8962
 8963                Some((element, origin))
 8964            }
 8965        }
 8966    }
 8967
 8968    fn render_edit_prediction_modifier_jump_popover(
 8969        &mut self,
 8970        text_bounds: &Bounds<Pixels>,
 8971        content_origin: gpui::Point<Pixels>,
 8972        visible_row_range: Range<DisplayRow>,
 8973        line_layouts: &[LineWithInvisibles],
 8974        line_height: Pixels,
 8975        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8976        newest_selection_head: Option<DisplayPoint>,
 8977        target_display_point: DisplayPoint,
 8978        window: &mut Window,
 8979        cx: &mut App,
 8980    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8981        let scrolled_content_origin =
 8982            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8983
 8984        const SCROLL_PADDING_Y: Pixels = px(12.);
 8985
 8986        if target_display_point.row() < visible_row_range.start {
 8987            return self.render_edit_prediction_scroll_popover(
 8988                |_| SCROLL_PADDING_Y,
 8989                IconName::ArrowUp,
 8990                visible_row_range,
 8991                line_layouts,
 8992                newest_selection_head,
 8993                scrolled_content_origin,
 8994                window,
 8995                cx,
 8996            );
 8997        } else if target_display_point.row() >= visible_row_range.end {
 8998            return self.render_edit_prediction_scroll_popover(
 8999                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9000                IconName::ArrowDown,
 9001                visible_row_range,
 9002                line_layouts,
 9003                newest_selection_head,
 9004                scrolled_content_origin,
 9005                window,
 9006                cx,
 9007            );
 9008        }
 9009
 9010        const POLE_WIDTH: Pixels = px(2.);
 9011
 9012        let line_layout =
 9013            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9014        let target_column = target_display_point.column() as usize;
 9015
 9016        let target_x = line_layout.x_for_index(target_column);
 9017        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9018            - scroll_pixel_position.y;
 9019
 9020        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9021
 9022        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9023        border_color.l += 0.001;
 9024
 9025        let mut element = v_flex()
 9026            .items_end()
 9027            .when(flag_on_right, |el| el.items_start())
 9028            .child(if flag_on_right {
 9029                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9030                    .rounded_bl(px(0.))
 9031                    .rounded_tl(px(0.))
 9032                    .border_l_2()
 9033                    .border_color(border_color)
 9034            } else {
 9035                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9036                    .rounded_br(px(0.))
 9037                    .rounded_tr(px(0.))
 9038                    .border_r_2()
 9039                    .border_color(border_color)
 9040            })
 9041            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9042            .into_any();
 9043
 9044        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9045
 9046        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9047            - point(
 9048                if flag_on_right {
 9049                    POLE_WIDTH
 9050                } else {
 9051                    size.width - POLE_WIDTH
 9052                },
 9053                size.height - line_height,
 9054            );
 9055
 9056        origin.x = origin.x.max(content_origin.x);
 9057
 9058        element.prepaint_at(origin, window, cx);
 9059
 9060        Some((element, origin))
 9061    }
 9062
 9063    fn render_edit_prediction_scroll_popover(
 9064        &mut self,
 9065        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9066        scroll_icon: IconName,
 9067        visible_row_range: Range<DisplayRow>,
 9068        line_layouts: &[LineWithInvisibles],
 9069        newest_selection_head: Option<DisplayPoint>,
 9070        scrolled_content_origin: gpui::Point<Pixels>,
 9071        window: &mut Window,
 9072        cx: &mut App,
 9073    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9074        let mut element = self
 9075            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9076            .into_any();
 9077
 9078        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9079
 9080        let cursor = newest_selection_head?;
 9081        let cursor_row_layout =
 9082            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9083        let cursor_column = cursor.column() as usize;
 9084
 9085        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9086
 9087        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9088
 9089        element.prepaint_at(origin, window, cx);
 9090        Some((element, origin))
 9091    }
 9092
 9093    fn render_edit_prediction_eager_jump_popover(
 9094        &mut self,
 9095        text_bounds: &Bounds<Pixels>,
 9096        content_origin: gpui::Point<Pixels>,
 9097        editor_snapshot: &EditorSnapshot,
 9098        visible_row_range: Range<DisplayRow>,
 9099        scroll_top: ScrollOffset,
 9100        scroll_bottom: ScrollOffset,
 9101        line_height: Pixels,
 9102        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9103        target_display_point: DisplayPoint,
 9104        editor_width: Pixels,
 9105        window: &mut Window,
 9106        cx: &mut App,
 9107    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9108        if target_display_point.row().as_f64() < scroll_top {
 9109            let mut element = self
 9110                .render_edit_prediction_line_popover(
 9111                    "Jump to Edit",
 9112                    Some(IconName::ArrowUp),
 9113                    window,
 9114                    cx,
 9115                )
 9116                .into_any();
 9117
 9118            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9119            let offset = point(
 9120                (text_bounds.size.width - size.width) / 2.,
 9121                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9122            );
 9123
 9124            let origin = text_bounds.origin + offset;
 9125            element.prepaint_at(origin, window, cx);
 9126            Some((element, origin))
 9127        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9128            let mut element = self
 9129                .render_edit_prediction_line_popover(
 9130                    "Jump to Edit",
 9131                    Some(IconName::ArrowDown),
 9132                    window,
 9133                    cx,
 9134                )
 9135                .into_any();
 9136
 9137            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9138            let offset = point(
 9139                (text_bounds.size.width - size.width) / 2.,
 9140                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9141            );
 9142
 9143            let origin = text_bounds.origin + offset;
 9144            element.prepaint_at(origin, window, cx);
 9145            Some((element, origin))
 9146        } else {
 9147            self.render_edit_prediction_end_of_line_popover(
 9148                "Jump to Edit",
 9149                editor_snapshot,
 9150                visible_row_range,
 9151                target_display_point,
 9152                line_height,
 9153                scroll_pixel_position,
 9154                content_origin,
 9155                editor_width,
 9156                window,
 9157                cx,
 9158            )
 9159        }
 9160    }
 9161
 9162    fn render_edit_prediction_end_of_line_popover(
 9163        self: &mut Editor,
 9164        label: &'static str,
 9165        editor_snapshot: &EditorSnapshot,
 9166        visible_row_range: Range<DisplayRow>,
 9167        target_display_point: DisplayPoint,
 9168        line_height: Pixels,
 9169        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9170        content_origin: gpui::Point<Pixels>,
 9171        editor_width: Pixels,
 9172        window: &mut Window,
 9173        cx: &mut App,
 9174    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9175        let target_line_end = DisplayPoint::new(
 9176            target_display_point.row(),
 9177            editor_snapshot.line_len(target_display_point.row()),
 9178        );
 9179
 9180        let mut element = self
 9181            .render_edit_prediction_line_popover(label, None, window, cx)
 9182            .into_any();
 9183
 9184        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9185
 9186        let line_origin =
 9187            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9188
 9189        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9190        let mut origin = start_point
 9191            + line_origin
 9192            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9193        origin.x = origin.x.max(content_origin.x);
 9194
 9195        let max_x = content_origin.x + editor_width - size.width;
 9196
 9197        if origin.x > max_x {
 9198            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9199
 9200            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9201                origin.y += offset;
 9202                IconName::ArrowUp
 9203            } else {
 9204                origin.y -= offset;
 9205                IconName::ArrowDown
 9206            };
 9207
 9208            element = self
 9209                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9210                .into_any();
 9211
 9212            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9213
 9214            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9215        }
 9216
 9217        element.prepaint_at(origin, window, cx);
 9218        Some((element, origin))
 9219    }
 9220
 9221    fn render_edit_prediction_diff_popover(
 9222        self: &Editor,
 9223        text_bounds: &Bounds<Pixels>,
 9224        content_origin: gpui::Point<Pixels>,
 9225        right_margin: Pixels,
 9226        editor_snapshot: &EditorSnapshot,
 9227        visible_row_range: Range<DisplayRow>,
 9228        line_layouts: &[LineWithInvisibles],
 9229        line_height: Pixels,
 9230        scroll_position: gpui::Point<ScrollOffset>,
 9231        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9232        newest_selection_head: Option<DisplayPoint>,
 9233        editor_width: Pixels,
 9234        style: &EditorStyle,
 9235        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9236        edit_preview: &Option<language::EditPreview>,
 9237        snapshot: &language::BufferSnapshot,
 9238        window: &mut Window,
 9239        cx: &mut App,
 9240    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9241        let edit_start = edits
 9242            .first()
 9243            .unwrap()
 9244            .0
 9245            .start
 9246            .to_display_point(editor_snapshot);
 9247        let edit_end = edits
 9248            .last()
 9249            .unwrap()
 9250            .0
 9251            .end
 9252            .to_display_point(editor_snapshot);
 9253
 9254        let is_visible = visible_row_range.contains(&edit_start.row())
 9255            || visible_row_range.contains(&edit_end.row());
 9256        if !is_visible {
 9257            return None;
 9258        }
 9259
 9260        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9261            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9262        } else {
 9263            // Fallback for providers without edit_preview
 9264            crate::edit_prediction_fallback_text(edits, cx)
 9265        };
 9266
 9267        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9268        let line_count = highlighted_edits.text.lines().count();
 9269
 9270        const BORDER_WIDTH: Pixels = px(1.);
 9271
 9272        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9273        let has_keybind = keybind.is_some();
 9274
 9275        let mut element = h_flex()
 9276            .items_start()
 9277            .child(
 9278                h_flex()
 9279                    .bg(cx.theme().colors().editor_background)
 9280                    .border(BORDER_WIDTH)
 9281                    .shadow_xs()
 9282                    .border_color(cx.theme().colors().border)
 9283                    .rounded_l_lg()
 9284                    .when(line_count > 1, |el| el.rounded_br_lg())
 9285                    .pr_1()
 9286                    .child(styled_text),
 9287            )
 9288            .child(
 9289                h_flex()
 9290                    .h(line_height + BORDER_WIDTH * 2.)
 9291                    .px_1p5()
 9292                    .gap_1()
 9293                    // Workaround: For some reason, there's a gap if we don't do this
 9294                    .ml(-BORDER_WIDTH)
 9295                    .shadow(vec![gpui::BoxShadow {
 9296                        color: gpui::black().opacity(0.05),
 9297                        offset: point(px(1.), px(1.)),
 9298                        blur_radius: px(2.),
 9299                        spread_radius: px(0.),
 9300                    }])
 9301                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9302                    .border(BORDER_WIDTH)
 9303                    .border_color(cx.theme().colors().border)
 9304                    .rounded_r_lg()
 9305                    .id("edit_prediction_diff_popover_keybind")
 9306                    .when(!has_keybind, |el| {
 9307                        let status_colors = cx.theme().status();
 9308
 9309                        el.bg(status_colors.error_background)
 9310                            .border_color(status_colors.error.opacity(0.6))
 9311                            .child(Icon::new(IconName::Info).color(Color::Error))
 9312                            .cursor_default()
 9313                            .hoverable_tooltip(move |_window, cx| {
 9314                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9315                            })
 9316                    })
 9317                    .children(keybind),
 9318            )
 9319            .into_any();
 9320
 9321        let longest_row =
 9322            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9323        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9324            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9325        } else {
 9326            layout_line(
 9327                longest_row,
 9328                editor_snapshot,
 9329                style,
 9330                editor_width,
 9331                |_| false,
 9332                window,
 9333                cx,
 9334            )
 9335            .width
 9336        };
 9337
 9338        let viewport_bounds =
 9339            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9340                right: -right_margin,
 9341                ..Default::default()
 9342            });
 9343
 9344        let x_after_longest = Pixels::from(
 9345            ScrollPixelOffset::from(
 9346                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9347            ) - scroll_pixel_position.x,
 9348        );
 9349
 9350        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9351
 9352        // Fully visible if it can be displayed within the window (allow overlapping other
 9353        // panes). However, this is only allowed if the popover starts within text_bounds.
 9354        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9355            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9356
 9357        let mut origin = if can_position_to_the_right {
 9358            point(
 9359                x_after_longest,
 9360                text_bounds.origin.y
 9361                    + Pixels::from(
 9362                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9363                            - scroll_pixel_position.y,
 9364                    ),
 9365            )
 9366        } else {
 9367            let cursor_row = newest_selection_head.map(|head| head.row());
 9368            let above_edit = edit_start
 9369                .row()
 9370                .0
 9371                .checked_sub(line_count as u32)
 9372                .map(DisplayRow);
 9373            let below_edit = Some(edit_end.row() + 1);
 9374            let above_cursor =
 9375                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9376            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9377
 9378            // Place the edit popover adjacent to the edit if there is a location
 9379            // available that is onscreen and does not obscure the cursor. Otherwise,
 9380            // place it adjacent to the cursor.
 9381            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9382                .into_iter()
 9383                .flatten()
 9384                .find(|&start_row| {
 9385                    let end_row = start_row + line_count as u32;
 9386                    visible_row_range.contains(&start_row)
 9387                        && visible_row_range.contains(&end_row)
 9388                        && cursor_row
 9389                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9390                })?;
 9391
 9392            content_origin
 9393                + point(
 9394                    Pixels::from(-scroll_pixel_position.x),
 9395                    Pixels::from(
 9396                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9397                    ),
 9398                )
 9399        };
 9400
 9401        origin.x -= BORDER_WIDTH;
 9402
 9403        window.defer_draw(element, origin, 1);
 9404
 9405        // Do not return an element, since it will already be drawn due to defer_draw.
 9406        None
 9407    }
 9408
 9409    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9410        px(30.)
 9411    }
 9412
 9413    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9414        if self.read_only(cx) {
 9415            cx.theme().players().read_only()
 9416        } else {
 9417            self.style.as_ref().unwrap().local_player
 9418        }
 9419    }
 9420
 9421    fn render_edit_prediction_accept_keybind(
 9422        &self,
 9423        window: &mut Window,
 9424        cx: &mut App,
 9425    ) -> Option<AnyElement> {
 9426        let accept_binding =
 9427            self.accept_edit_prediction_keybind(EditPredictionGranularity::Full, window, cx);
 9428        let accept_keystroke = accept_binding.keystroke()?;
 9429
 9430        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9431
 9432        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9433            Color::Accent
 9434        } else {
 9435            Color::Muted
 9436        };
 9437
 9438        h_flex()
 9439            .px_0p5()
 9440            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9441            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9442            .text_size(TextSize::XSmall.rems(cx))
 9443            .child(h_flex().children(ui::render_modifiers(
 9444                accept_keystroke.modifiers(),
 9445                PlatformStyle::platform(),
 9446                Some(modifiers_color),
 9447                Some(IconSize::XSmall.rems().into()),
 9448                true,
 9449            )))
 9450            .when(is_platform_style_mac, |parent| {
 9451                parent.child(accept_keystroke.key().to_string())
 9452            })
 9453            .when(!is_platform_style_mac, |parent| {
 9454                parent.child(
 9455                    Key::new(
 9456                        util::capitalize(accept_keystroke.key()),
 9457                        Some(Color::Default),
 9458                    )
 9459                    .size(Some(IconSize::XSmall.rems().into())),
 9460                )
 9461            })
 9462            .into_any()
 9463            .into()
 9464    }
 9465
 9466    fn render_edit_prediction_line_popover(
 9467        &self,
 9468        label: impl Into<SharedString>,
 9469        icon: Option<IconName>,
 9470        window: &mut Window,
 9471        cx: &mut App,
 9472    ) -> Stateful<Div> {
 9473        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9474
 9475        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9476        let has_keybind = keybind.is_some();
 9477
 9478        h_flex()
 9479            .id("ep-line-popover")
 9480            .py_0p5()
 9481            .pl_1()
 9482            .pr(padding_right)
 9483            .gap_1()
 9484            .rounded_md()
 9485            .border_1()
 9486            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9487            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9488            .shadow_xs()
 9489            .when(!has_keybind, |el| {
 9490                let status_colors = cx.theme().status();
 9491
 9492                el.bg(status_colors.error_background)
 9493                    .border_color(status_colors.error.opacity(0.6))
 9494                    .pl_2()
 9495                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9496                    .cursor_default()
 9497                    .hoverable_tooltip(move |_window, cx| {
 9498                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9499                    })
 9500            })
 9501            .children(keybind)
 9502            .child(
 9503                Label::new(label)
 9504                    .size(LabelSize::Small)
 9505                    .when(!has_keybind, |el| {
 9506                        el.color(cx.theme().status().error.into()).strikethrough()
 9507                    }),
 9508            )
 9509            .when(!has_keybind, |el| {
 9510                el.child(
 9511                    h_flex().ml_1().child(
 9512                        Icon::new(IconName::Info)
 9513                            .size(IconSize::Small)
 9514                            .color(cx.theme().status().error.into()),
 9515                    ),
 9516                )
 9517            })
 9518            .when_some(icon, |element, icon| {
 9519                element.child(
 9520                    div()
 9521                        .mt(px(1.5))
 9522                        .child(Icon::new(icon).size(IconSize::Small)),
 9523                )
 9524            })
 9525    }
 9526
 9527    fn render_edit_prediction_jump_outside_popover(
 9528        &self,
 9529        snapshot: &BufferSnapshot,
 9530        window: &mut Window,
 9531        cx: &mut App,
 9532    ) -> Stateful<Div> {
 9533        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9534        let has_keybind = keybind.is_some();
 9535
 9536        let file_name = snapshot
 9537            .file()
 9538            .map(|file| SharedString::new(file.file_name(cx)))
 9539            .unwrap_or(SharedString::new_static("untitled"));
 9540
 9541        h_flex()
 9542            .id("ep-jump-outside-popover")
 9543            .py_1()
 9544            .px_2()
 9545            .gap_1()
 9546            .rounded_md()
 9547            .border_1()
 9548            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9549            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9550            .shadow_xs()
 9551            .when(!has_keybind, |el| {
 9552                let status_colors = cx.theme().status();
 9553
 9554                el.bg(status_colors.error_background)
 9555                    .border_color(status_colors.error.opacity(0.6))
 9556                    .pl_2()
 9557                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9558                    .cursor_default()
 9559                    .hoverable_tooltip(move |_window, cx| {
 9560                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9561                    })
 9562            })
 9563            .children(keybind)
 9564            .child(
 9565                Label::new(file_name)
 9566                    .size(LabelSize::Small)
 9567                    .buffer_font(cx)
 9568                    .when(!has_keybind, |el| {
 9569                        el.color(cx.theme().status().error.into()).strikethrough()
 9570                    }),
 9571            )
 9572            .when(!has_keybind, |el| {
 9573                el.child(
 9574                    h_flex().ml_1().child(
 9575                        Icon::new(IconName::Info)
 9576                            .size(IconSize::Small)
 9577                            .color(cx.theme().status().error.into()),
 9578                    ),
 9579                )
 9580            })
 9581            .child(
 9582                div()
 9583                    .mt(px(1.5))
 9584                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9585            )
 9586    }
 9587
 9588    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9589        let accent_color = cx.theme().colors().text_accent;
 9590        let editor_bg_color = cx.theme().colors().editor_background;
 9591        editor_bg_color.blend(accent_color.opacity(0.1))
 9592    }
 9593
 9594    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9595        let accent_color = cx.theme().colors().text_accent;
 9596        let editor_bg_color = cx.theme().colors().editor_background;
 9597        editor_bg_color.blend(accent_color.opacity(0.6))
 9598    }
 9599    fn get_prediction_provider_icon_name(
 9600        provider: &Option<RegisteredEditPredictionDelegate>,
 9601    ) -> IconName {
 9602        match provider {
 9603            Some(provider) => match provider.provider.name() {
 9604                "copilot" => IconName::Copilot,
 9605                "supermaven" => IconName::Supermaven,
 9606                _ => IconName::ZedPredict,
 9607            },
 9608            None => IconName::ZedPredict,
 9609        }
 9610    }
 9611
 9612    fn render_edit_prediction_cursor_popover(
 9613        &self,
 9614        min_width: Pixels,
 9615        max_width: Pixels,
 9616        cursor_point: Point,
 9617        style: &EditorStyle,
 9618        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9619        _window: &Window,
 9620        cx: &mut Context<Editor>,
 9621    ) -> Option<AnyElement> {
 9622        let provider = self.edit_prediction_provider.as_ref()?;
 9623        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9624
 9625        let is_refreshing = provider.provider.is_refreshing(cx);
 9626
 9627        fn pending_completion_container(icon: IconName) -> Div {
 9628            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9629        }
 9630
 9631        let completion = match &self.active_edit_prediction {
 9632            Some(prediction) => {
 9633                if !self.has_visible_completions_menu() {
 9634                    const RADIUS: Pixels = px(6.);
 9635                    const BORDER_WIDTH: Pixels = px(1.);
 9636
 9637                    return Some(
 9638                        h_flex()
 9639                            .elevation_2(cx)
 9640                            .border(BORDER_WIDTH)
 9641                            .border_color(cx.theme().colors().border)
 9642                            .when(accept_keystroke.is_none(), |el| {
 9643                                el.border_color(cx.theme().status().error)
 9644                            })
 9645                            .rounded(RADIUS)
 9646                            .rounded_tl(px(0.))
 9647                            .overflow_hidden()
 9648                            .child(div().px_1p5().child(match &prediction.completion {
 9649                                EditPrediction::MoveWithin { target, snapshot } => {
 9650                                    use text::ToPoint as _;
 9651                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9652                                    {
 9653                                        Icon::new(IconName::ZedPredictDown)
 9654                                    } else {
 9655                                        Icon::new(IconName::ZedPredictUp)
 9656                                    }
 9657                                }
 9658                                EditPrediction::MoveOutside { .. } => {
 9659                                    // TODO [zeta2] custom icon for external jump?
 9660                                    Icon::new(provider_icon)
 9661                                }
 9662                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9663                            }))
 9664                            .child(
 9665                                h_flex()
 9666                                    .gap_1()
 9667                                    .py_1()
 9668                                    .px_2()
 9669                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9670                                    .border_l_1()
 9671                                    .border_color(cx.theme().colors().border)
 9672                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9673                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9674                                        el.child(
 9675                                            Label::new("Hold")
 9676                                                .size(LabelSize::Small)
 9677                                                .when(accept_keystroke.is_none(), |el| {
 9678                                                    el.strikethrough()
 9679                                                })
 9680                                                .line_height_style(LineHeightStyle::UiLabel),
 9681                                        )
 9682                                    })
 9683                                    .id("edit_prediction_cursor_popover_keybind")
 9684                                    .when(accept_keystroke.is_none(), |el| {
 9685                                        let status_colors = cx.theme().status();
 9686
 9687                                        el.bg(status_colors.error_background)
 9688                                            .border_color(status_colors.error.opacity(0.6))
 9689                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9690                                            .cursor_default()
 9691                                            .hoverable_tooltip(move |_window, cx| {
 9692                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9693                                                    .into()
 9694                                            })
 9695                                    })
 9696                                    .when_some(
 9697                                        accept_keystroke.as_ref(),
 9698                                        |el, accept_keystroke| {
 9699                                            el.child(h_flex().children(ui::render_modifiers(
 9700                                                accept_keystroke.modifiers(),
 9701                                                PlatformStyle::platform(),
 9702                                                Some(Color::Default),
 9703                                                Some(IconSize::XSmall.rems().into()),
 9704                                                false,
 9705                                            )))
 9706                                        },
 9707                                    ),
 9708                            )
 9709                            .into_any(),
 9710                    );
 9711                }
 9712
 9713                self.render_edit_prediction_cursor_popover_preview(
 9714                    prediction,
 9715                    cursor_point,
 9716                    style,
 9717                    cx,
 9718                )?
 9719            }
 9720
 9721            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9722                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9723                    stale_completion,
 9724                    cursor_point,
 9725                    style,
 9726                    cx,
 9727                )?,
 9728
 9729                None => pending_completion_container(provider_icon)
 9730                    .child(Label::new("...").size(LabelSize::Small)),
 9731            },
 9732
 9733            None => pending_completion_container(provider_icon)
 9734                .child(Label::new("...").size(LabelSize::Small)),
 9735        };
 9736
 9737        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9738            completion
 9739                .with_animation(
 9740                    "loading-completion",
 9741                    Animation::new(Duration::from_secs(2))
 9742                        .repeat()
 9743                        .with_easing(pulsating_between(0.4, 0.8)),
 9744                    |label, delta| label.opacity(delta),
 9745                )
 9746                .into_any_element()
 9747        } else {
 9748            completion.into_any_element()
 9749        };
 9750
 9751        let has_completion = self.active_edit_prediction.is_some();
 9752
 9753        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9754        Some(
 9755            h_flex()
 9756                .min_w(min_width)
 9757                .max_w(max_width)
 9758                .flex_1()
 9759                .elevation_2(cx)
 9760                .border_color(cx.theme().colors().border)
 9761                .child(
 9762                    div()
 9763                        .flex_1()
 9764                        .py_1()
 9765                        .px_2()
 9766                        .overflow_hidden()
 9767                        .child(completion),
 9768                )
 9769                .when_some(accept_keystroke, |el, accept_keystroke| {
 9770                    if !accept_keystroke.modifiers().modified() {
 9771                        return el;
 9772                    }
 9773
 9774                    el.child(
 9775                        h_flex()
 9776                            .h_full()
 9777                            .border_l_1()
 9778                            .rounded_r_lg()
 9779                            .border_color(cx.theme().colors().border)
 9780                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9781                            .gap_1()
 9782                            .py_1()
 9783                            .px_2()
 9784                            .child(
 9785                                h_flex()
 9786                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9787                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9788                                    .child(h_flex().children(ui::render_modifiers(
 9789                                        accept_keystroke.modifiers(),
 9790                                        PlatformStyle::platform(),
 9791                                        Some(if !has_completion {
 9792                                            Color::Muted
 9793                                        } else {
 9794                                            Color::Default
 9795                                        }),
 9796                                        None,
 9797                                        false,
 9798                                    ))),
 9799                            )
 9800                            .child(Label::new("Preview").into_any_element())
 9801                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9802                    )
 9803                })
 9804                .into_any(),
 9805        )
 9806    }
 9807
 9808    fn render_edit_prediction_cursor_popover_preview(
 9809        &self,
 9810        completion: &EditPredictionState,
 9811        cursor_point: Point,
 9812        style: &EditorStyle,
 9813        cx: &mut Context<Editor>,
 9814    ) -> Option<Div> {
 9815        use text::ToPoint as _;
 9816
 9817        fn render_relative_row_jump(
 9818            prefix: impl Into<String>,
 9819            current_row: u32,
 9820            target_row: u32,
 9821        ) -> Div {
 9822            let (row_diff, arrow) = if target_row < current_row {
 9823                (current_row - target_row, IconName::ArrowUp)
 9824            } else {
 9825                (target_row - current_row, IconName::ArrowDown)
 9826            };
 9827
 9828            h_flex()
 9829                .child(
 9830                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9831                        .color(Color::Muted)
 9832                        .size(LabelSize::Small),
 9833                )
 9834                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9835        }
 9836
 9837        let supports_jump = self
 9838            .edit_prediction_provider
 9839            .as_ref()
 9840            .map(|provider| provider.provider.supports_jump_to_edit())
 9841            .unwrap_or(true);
 9842
 9843        match &completion.completion {
 9844            EditPrediction::MoveWithin {
 9845                target, snapshot, ..
 9846            } => {
 9847                if !supports_jump {
 9848                    return None;
 9849                }
 9850
 9851                Some(
 9852                    h_flex()
 9853                        .px_2()
 9854                        .gap_2()
 9855                        .flex_1()
 9856                        .child(
 9857                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9858                                Icon::new(IconName::ZedPredictDown)
 9859                            } else {
 9860                                Icon::new(IconName::ZedPredictUp)
 9861                            },
 9862                        )
 9863                        .child(Label::new("Jump to Edit")),
 9864                )
 9865            }
 9866            EditPrediction::MoveOutside { snapshot, .. } => {
 9867                let file_name = snapshot
 9868                    .file()
 9869                    .map(|file| file.file_name(cx))
 9870                    .unwrap_or("untitled");
 9871                Some(
 9872                    h_flex()
 9873                        .px_2()
 9874                        .gap_2()
 9875                        .flex_1()
 9876                        .child(Icon::new(IconName::ZedPredict))
 9877                        .child(Label::new(format!("Jump to {file_name}"))),
 9878                )
 9879            }
 9880            EditPrediction::Edit {
 9881                edits,
 9882                edit_preview,
 9883                snapshot,
 9884                display_mode: _,
 9885            } => {
 9886                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9887
 9888                let (highlighted_edits, has_more_lines) =
 9889                    if let Some(edit_preview) = edit_preview.as_ref() {
 9890                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9891                            .first_line_preview()
 9892                    } else {
 9893                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9894                    };
 9895
 9896                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9897                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9898
 9899                let preview = h_flex()
 9900                    .gap_1()
 9901                    .min_w_16()
 9902                    .child(styled_text)
 9903                    .when(has_more_lines, |parent| parent.child(""));
 9904
 9905                let left = if supports_jump && first_edit_row != cursor_point.row {
 9906                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9907                        .into_any_element()
 9908                } else {
 9909                    let icon_name =
 9910                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9911                    Icon::new(icon_name).into_any_element()
 9912                };
 9913
 9914                Some(
 9915                    h_flex()
 9916                        .h_full()
 9917                        .flex_1()
 9918                        .gap_2()
 9919                        .pr_1()
 9920                        .overflow_x_hidden()
 9921                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9922                        .child(left)
 9923                        .child(preview),
 9924                )
 9925            }
 9926        }
 9927    }
 9928
 9929    pub fn render_context_menu(
 9930        &mut self,
 9931        max_height_in_lines: u32,
 9932        window: &mut Window,
 9933        cx: &mut Context<Editor>,
 9934    ) -> Option<AnyElement> {
 9935        let menu = self.context_menu.borrow();
 9936        let menu = menu.as_ref()?;
 9937        if !menu.visible() {
 9938            return None;
 9939        };
 9940        self.style
 9941            .as_ref()
 9942            .map(|style| menu.render(style, max_height_in_lines, window, cx))
 9943    }
 9944
 9945    fn render_context_menu_aside(
 9946        &mut self,
 9947        max_size: Size<Pixels>,
 9948        window: &mut Window,
 9949        cx: &mut Context<Editor>,
 9950    ) -> Option<AnyElement> {
 9951        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9952            if menu.visible() {
 9953                menu.render_aside(max_size, window, cx)
 9954            } else {
 9955                None
 9956            }
 9957        })
 9958    }
 9959
 9960    fn hide_context_menu(
 9961        &mut self,
 9962        window: &mut Window,
 9963        cx: &mut Context<Self>,
 9964    ) -> Option<CodeContextMenu> {
 9965        cx.notify();
 9966        self.completion_tasks.clear();
 9967        let context_menu = self.context_menu.borrow_mut().take();
 9968        self.stale_edit_prediction_in_menu.take();
 9969        self.update_visible_edit_prediction(window, cx);
 9970        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9971            && let Some(completion_provider) = &self.completion_provider
 9972        {
 9973            completion_provider.selection_changed(None, window, cx);
 9974        }
 9975        context_menu
 9976    }
 9977
 9978    fn show_snippet_choices(
 9979        &mut self,
 9980        choices: &Vec<String>,
 9981        selection: Range<Anchor>,
 9982        cx: &mut Context<Self>,
 9983    ) {
 9984        let Some((_, buffer, _)) = self
 9985            .buffer()
 9986            .read(cx)
 9987            .excerpt_containing(selection.start, cx)
 9988        else {
 9989            return;
 9990        };
 9991        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9992        else {
 9993            return;
 9994        };
 9995        if buffer != end_buffer {
 9996            log::error!("expected anchor range to have matching buffer IDs");
 9997            return;
 9998        }
 9999
10000        let id = post_inc(&mut self.next_completion_id);
10001        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10002        let mut context_menu = self.context_menu.borrow_mut();
10003        let old_menu = context_menu.take();
10004        *context_menu = Some(CodeContextMenu::Completions(
10005            CompletionsMenu::new_snippet_choices(
10006                id,
10007                true,
10008                choices,
10009                selection,
10010                buffer,
10011                old_menu.map(|menu| menu.primary_scroll_handle()),
10012                snippet_sort_order,
10013            ),
10014        ));
10015    }
10016
10017    pub fn insert_snippet(
10018        &mut self,
10019        insertion_ranges: &[Range<MultiBufferOffset>],
10020        snippet: Snippet,
10021        window: &mut Window,
10022        cx: &mut Context<Self>,
10023    ) -> Result<()> {
10024        struct Tabstop<T> {
10025            is_end_tabstop: bool,
10026            ranges: Vec<Range<T>>,
10027            choices: Option<Vec<String>>,
10028        }
10029
10030        let tabstops = self.buffer.update(cx, |buffer, cx| {
10031            let snippet_text: Arc<str> = snippet.text.clone().into();
10032            let edits = insertion_ranges
10033                .iter()
10034                .cloned()
10035                .map(|range| (range, snippet_text.clone()));
10036            let autoindent_mode = AutoindentMode::Block {
10037                original_indent_columns: Vec::new(),
10038            };
10039            buffer.edit(edits, Some(autoindent_mode), cx);
10040
10041            let snapshot = &*buffer.read(cx);
10042            let snippet = &snippet;
10043            snippet
10044                .tabstops
10045                .iter()
10046                .map(|tabstop| {
10047                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10048                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10049                    });
10050                    let mut tabstop_ranges = tabstop
10051                        .ranges
10052                        .iter()
10053                        .flat_map(|tabstop_range| {
10054                            let mut delta = 0_isize;
10055                            insertion_ranges.iter().map(move |insertion_range| {
10056                                let insertion_start = insertion_range.start + delta;
10057                                delta += snippet.text.len() as isize
10058                                    - (insertion_range.end - insertion_range.start) as isize;
10059
10060                                let start =
10061                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10062                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10063                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10064                            })
10065                        })
10066                        .collect::<Vec<_>>();
10067                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10068
10069                    Tabstop {
10070                        is_end_tabstop,
10071                        ranges: tabstop_ranges,
10072                        choices: tabstop.choices.clone(),
10073                    }
10074                })
10075                .collect::<Vec<_>>()
10076        });
10077        if let Some(tabstop) = tabstops.first() {
10078            self.change_selections(Default::default(), window, cx, |s| {
10079                // Reverse order so that the first range is the newest created selection.
10080                // Completions will use it and autoscroll will prioritize it.
10081                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10082            });
10083
10084            if let Some(choices) = &tabstop.choices
10085                && let Some(selection) = tabstop.ranges.first()
10086            {
10087                self.show_snippet_choices(choices, selection.clone(), cx)
10088            }
10089
10090            // If we're already at the last tabstop and it's at the end of the snippet,
10091            // we're done, we don't need to keep the state around.
10092            if !tabstop.is_end_tabstop {
10093                let choices = tabstops
10094                    .iter()
10095                    .map(|tabstop| tabstop.choices.clone())
10096                    .collect();
10097
10098                let ranges = tabstops
10099                    .into_iter()
10100                    .map(|tabstop| tabstop.ranges)
10101                    .collect::<Vec<_>>();
10102
10103                self.snippet_stack.push(SnippetState {
10104                    active_index: 0,
10105                    ranges,
10106                    choices,
10107                });
10108            }
10109
10110            // Check whether the just-entered snippet ends with an auto-closable bracket.
10111            if self.autoclose_regions.is_empty() {
10112                let snapshot = self.buffer.read(cx).snapshot(cx);
10113                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10114                    let selection_head = selection.head();
10115                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10116                        continue;
10117                    };
10118
10119                    let mut bracket_pair = None;
10120                    let max_lookup_length = scope
10121                        .brackets()
10122                        .map(|(pair, _)| {
10123                            pair.start
10124                                .as_str()
10125                                .chars()
10126                                .count()
10127                                .max(pair.end.as_str().chars().count())
10128                        })
10129                        .max();
10130                    if let Some(max_lookup_length) = max_lookup_length {
10131                        let next_text = snapshot
10132                            .chars_at(selection_head)
10133                            .take(max_lookup_length)
10134                            .collect::<String>();
10135                        let prev_text = snapshot
10136                            .reversed_chars_at(selection_head)
10137                            .take(max_lookup_length)
10138                            .collect::<String>();
10139
10140                        for (pair, enabled) in scope.brackets() {
10141                            if enabled
10142                                && pair.close
10143                                && prev_text.starts_with(pair.start.as_str())
10144                                && next_text.starts_with(pair.end.as_str())
10145                            {
10146                                bracket_pair = Some(pair.clone());
10147                                break;
10148                            }
10149                        }
10150                    }
10151
10152                    if let Some(pair) = bracket_pair {
10153                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10154                        let autoclose_enabled =
10155                            self.use_autoclose && snapshot_settings.use_autoclose;
10156                        if autoclose_enabled {
10157                            let start = snapshot.anchor_after(selection_head);
10158                            let end = snapshot.anchor_after(selection_head);
10159                            self.autoclose_regions.push(AutocloseRegion {
10160                                selection_id: selection.id,
10161                                range: start..end,
10162                                pair,
10163                            });
10164                        }
10165                    }
10166                }
10167            }
10168        }
10169        Ok(())
10170    }
10171
10172    pub fn move_to_next_snippet_tabstop(
10173        &mut self,
10174        window: &mut Window,
10175        cx: &mut Context<Self>,
10176    ) -> bool {
10177        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10178    }
10179
10180    pub fn move_to_prev_snippet_tabstop(
10181        &mut self,
10182        window: &mut Window,
10183        cx: &mut Context<Self>,
10184    ) -> bool {
10185        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10186    }
10187
10188    pub fn move_to_snippet_tabstop(
10189        &mut self,
10190        bias: Bias,
10191        window: &mut Window,
10192        cx: &mut Context<Self>,
10193    ) -> bool {
10194        if let Some(mut snippet) = self.snippet_stack.pop() {
10195            match bias {
10196                Bias::Left => {
10197                    if snippet.active_index > 0 {
10198                        snippet.active_index -= 1;
10199                    } else {
10200                        self.snippet_stack.push(snippet);
10201                        return false;
10202                    }
10203                }
10204                Bias::Right => {
10205                    if snippet.active_index + 1 < snippet.ranges.len() {
10206                        snippet.active_index += 1;
10207                    } else {
10208                        self.snippet_stack.push(snippet);
10209                        return false;
10210                    }
10211                }
10212            }
10213            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10214                self.change_selections(Default::default(), window, cx, |s| {
10215                    // Reverse order so that the first range is the newest created selection.
10216                    // Completions will use it and autoscroll will prioritize it.
10217                    s.select_ranges(current_ranges.iter().rev().cloned())
10218                });
10219
10220                if let Some(choices) = &snippet.choices[snippet.active_index]
10221                    && let Some(selection) = current_ranges.first()
10222                {
10223                    self.show_snippet_choices(choices, selection.clone(), cx);
10224                }
10225
10226                // If snippet state is not at the last tabstop, push it back on the stack
10227                if snippet.active_index + 1 < snippet.ranges.len() {
10228                    self.snippet_stack.push(snippet);
10229                }
10230                return true;
10231            }
10232        }
10233
10234        false
10235    }
10236
10237    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10238        self.transact(window, cx, |this, window, cx| {
10239            this.select_all(&SelectAll, window, cx);
10240            this.insert("", window, cx);
10241        });
10242    }
10243
10244    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10245        if self.read_only(cx) {
10246            return;
10247        }
10248        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10249        self.transact(window, cx, |this, window, cx| {
10250            this.select_autoclose_pair(window, cx);
10251
10252            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10253
10254            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10255            if !this.linked_edit_ranges.is_empty() {
10256                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10257                let snapshot = this.buffer.read(cx).snapshot(cx);
10258
10259                for selection in selections.iter() {
10260                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10261                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10262                    if selection_start.buffer_id != selection_end.buffer_id {
10263                        continue;
10264                    }
10265                    if let Some(ranges) =
10266                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10267                    {
10268                        for (buffer, entries) in ranges {
10269                            linked_ranges.entry(buffer).or_default().extend(entries);
10270                        }
10271                    }
10272                }
10273            }
10274
10275            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10276            for selection in &mut selections {
10277                if selection.is_empty() {
10278                    let old_head = selection.head();
10279                    let mut new_head =
10280                        movement::left(&display_map, old_head.to_display_point(&display_map))
10281                            .to_point(&display_map);
10282                    if let Some((buffer, line_buffer_range)) = display_map
10283                        .buffer_snapshot()
10284                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10285                    {
10286                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10287                        let indent_len = match indent_size.kind {
10288                            IndentKind::Space => {
10289                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10290                            }
10291                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10292                        };
10293                        if old_head.column <= indent_size.len && old_head.column > 0 {
10294                            let indent_len = indent_len.get();
10295                            new_head = cmp::min(
10296                                new_head,
10297                                MultiBufferPoint::new(
10298                                    old_head.row,
10299                                    ((old_head.column - 1) / indent_len) * indent_len,
10300                                ),
10301                            );
10302                        }
10303                    }
10304
10305                    selection.set_head(new_head, SelectionGoal::None);
10306                }
10307            }
10308
10309            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10310            this.insert("", window, cx);
10311            let empty_str: Arc<str> = Arc::from("");
10312            for (buffer, edits) in linked_ranges {
10313                let snapshot = buffer.read(cx).snapshot();
10314                use text::ToPoint as TP;
10315
10316                let edits = edits
10317                    .into_iter()
10318                    .map(|range| {
10319                        let end_point = TP::to_point(&range.end, &snapshot);
10320                        let mut start_point = TP::to_point(&range.start, &snapshot);
10321
10322                        if end_point == start_point {
10323                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10324                                .saturating_sub(1);
10325                            start_point =
10326                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10327                        };
10328
10329                        (start_point..end_point, empty_str.clone())
10330                    })
10331                    .sorted_by_key(|(range, _)| range.start)
10332                    .collect::<Vec<_>>();
10333                buffer.update(cx, |this, cx| {
10334                    this.edit(edits, None, cx);
10335                })
10336            }
10337            this.refresh_edit_prediction(true, false, window, cx);
10338            refresh_linked_ranges(this, window, cx);
10339        });
10340    }
10341
10342    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10343        if self.read_only(cx) {
10344            return;
10345        }
10346        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10347        self.transact(window, cx, |this, window, cx| {
10348            this.change_selections(Default::default(), window, cx, |s| {
10349                s.move_with(|map, selection| {
10350                    if selection.is_empty() {
10351                        let cursor = movement::right(map, selection.head());
10352                        selection.end = cursor;
10353                        selection.reversed = true;
10354                        selection.goal = SelectionGoal::None;
10355                    }
10356                })
10357            });
10358            this.insert("", window, cx);
10359            this.refresh_edit_prediction(true, false, window, cx);
10360        });
10361    }
10362
10363    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10364        if self.mode.is_single_line() {
10365            cx.propagate();
10366            return;
10367        }
10368
10369        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10370        if self.move_to_prev_snippet_tabstop(window, cx) {
10371            return;
10372        }
10373        self.outdent(&Outdent, window, cx);
10374    }
10375
10376    pub fn next_snippet_tabstop(
10377        &mut self,
10378        _: &NextSnippetTabstop,
10379        window: &mut Window,
10380        cx: &mut Context<Self>,
10381    ) {
10382        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10383            cx.propagate();
10384            return;
10385        }
10386
10387        if self.move_to_next_snippet_tabstop(window, cx) {
10388            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10389            return;
10390        }
10391        cx.propagate();
10392    }
10393
10394    pub fn previous_snippet_tabstop(
10395        &mut self,
10396        _: &PreviousSnippetTabstop,
10397        window: &mut Window,
10398        cx: &mut Context<Self>,
10399    ) {
10400        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10401            cx.propagate();
10402            return;
10403        }
10404
10405        if self.move_to_prev_snippet_tabstop(window, cx) {
10406            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10407            return;
10408        }
10409        cx.propagate();
10410    }
10411
10412    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10413        if self.mode.is_single_line() {
10414            cx.propagate();
10415            return;
10416        }
10417
10418        if self.move_to_next_snippet_tabstop(window, cx) {
10419            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10420            return;
10421        }
10422        if self.read_only(cx) {
10423            return;
10424        }
10425        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10426        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10427        let buffer = self.buffer.read(cx);
10428        let snapshot = buffer.snapshot(cx);
10429        let rows_iter = selections.iter().map(|s| s.head().row);
10430        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10431
10432        let has_some_cursor_in_whitespace = selections
10433            .iter()
10434            .filter(|selection| selection.is_empty())
10435            .any(|selection| {
10436                let cursor = selection.head();
10437                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10438                cursor.column < current_indent.len
10439            });
10440
10441        let mut edits = Vec::new();
10442        let mut prev_edited_row = 0;
10443        let mut row_delta = 0;
10444        for selection in &mut selections {
10445            if selection.start.row != prev_edited_row {
10446                row_delta = 0;
10447            }
10448            prev_edited_row = selection.end.row;
10449
10450            // If the selection is non-empty, then increase the indentation of the selected lines.
10451            if !selection.is_empty() {
10452                row_delta =
10453                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10454                continue;
10455            }
10456
10457            let cursor = selection.head();
10458            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10459            if let Some(suggested_indent) =
10460                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10461            {
10462                // Don't do anything if already at suggested indent
10463                // and there is any other cursor which is not
10464                if has_some_cursor_in_whitespace
10465                    && cursor.column == current_indent.len
10466                    && current_indent.len == suggested_indent.len
10467                {
10468                    continue;
10469                }
10470
10471                // Adjust line and move cursor to suggested indent
10472                // if cursor is not at suggested indent
10473                if cursor.column < suggested_indent.len
10474                    && cursor.column <= current_indent.len
10475                    && current_indent.len <= suggested_indent.len
10476                {
10477                    selection.start = Point::new(cursor.row, suggested_indent.len);
10478                    selection.end = selection.start;
10479                    if row_delta == 0 {
10480                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10481                            cursor.row,
10482                            current_indent,
10483                            suggested_indent,
10484                        ));
10485                        row_delta = suggested_indent.len - current_indent.len;
10486                    }
10487                    continue;
10488                }
10489
10490                // If current indent is more than suggested indent
10491                // only move cursor to current indent and skip indent
10492                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10493                    selection.start = Point::new(cursor.row, current_indent.len);
10494                    selection.end = selection.start;
10495                    continue;
10496                }
10497            }
10498
10499            // Otherwise, insert a hard or soft tab.
10500            let settings = buffer.language_settings_at(cursor, cx);
10501            let tab_size = if settings.hard_tabs {
10502                IndentSize::tab()
10503            } else {
10504                let tab_size = settings.tab_size.get();
10505                let indent_remainder = snapshot
10506                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10507                    .flat_map(str::chars)
10508                    .fold(row_delta % tab_size, |counter: u32, c| {
10509                        if c == '\t' {
10510                            0
10511                        } else {
10512                            (counter + 1) % tab_size
10513                        }
10514                    });
10515
10516                let chars_to_next_tab_stop = tab_size - indent_remainder;
10517                IndentSize::spaces(chars_to_next_tab_stop)
10518            };
10519            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10520            selection.end = selection.start;
10521            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10522            row_delta += tab_size.len;
10523        }
10524
10525        self.transact(window, cx, |this, window, cx| {
10526            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10527            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10528            this.refresh_edit_prediction(true, false, window, cx);
10529        });
10530    }
10531
10532    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10533        if self.read_only(cx) {
10534            return;
10535        }
10536        if self.mode.is_single_line() {
10537            cx.propagate();
10538            return;
10539        }
10540
10541        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10542        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10543        let mut prev_edited_row = 0;
10544        let mut row_delta = 0;
10545        let mut edits = Vec::new();
10546        let buffer = self.buffer.read(cx);
10547        let snapshot = buffer.snapshot(cx);
10548        for selection in &mut selections {
10549            if selection.start.row != prev_edited_row {
10550                row_delta = 0;
10551            }
10552            prev_edited_row = selection.end.row;
10553
10554            row_delta =
10555                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10556        }
10557
10558        self.transact(window, cx, |this, window, cx| {
10559            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10560            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10561        });
10562    }
10563
10564    fn indent_selection(
10565        buffer: &MultiBuffer,
10566        snapshot: &MultiBufferSnapshot,
10567        selection: &mut Selection<Point>,
10568        edits: &mut Vec<(Range<Point>, String)>,
10569        delta_for_start_row: u32,
10570        cx: &App,
10571    ) -> u32 {
10572        let settings = buffer.language_settings_at(selection.start, cx);
10573        let tab_size = settings.tab_size.get();
10574        let indent_kind = if settings.hard_tabs {
10575            IndentKind::Tab
10576        } else {
10577            IndentKind::Space
10578        };
10579        let mut start_row = selection.start.row;
10580        let mut end_row = selection.end.row + 1;
10581
10582        // If a selection ends at the beginning of a line, don't indent
10583        // that last line.
10584        if selection.end.column == 0 && selection.end.row > selection.start.row {
10585            end_row -= 1;
10586        }
10587
10588        // Avoid re-indenting a row that has already been indented by a
10589        // previous selection, but still update this selection's column
10590        // to reflect that indentation.
10591        if delta_for_start_row > 0 {
10592            start_row += 1;
10593            selection.start.column += delta_for_start_row;
10594            if selection.end.row == selection.start.row {
10595                selection.end.column += delta_for_start_row;
10596            }
10597        }
10598
10599        let mut delta_for_end_row = 0;
10600        let has_multiple_rows = start_row + 1 != end_row;
10601        for row in start_row..end_row {
10602            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10603            let indent_delta = match (current_indent.kind, indent_kind) {
10604                (IndentKind::Space, IndentKind::Space) => {
10605                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10606                    IndentSize::spaces(columns_to_next_tab_stop)
10607                }
10608                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10609                (_, IndentKind::Tab) => IndentSize::tab(),
10610            };
10611
10612            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10613                0
10614            } else {
10615                selection.start.column
10616            };
10617            let row_start = Point::new(row, start);
10618            edits.push((
10619                row_start..row_start,
10620                indent_delta.chars().collect::<String>(),
10621            ));
10622
10623            // Update this selection's endpoints to reflect the indentation.
10624            if row == selection.start.row {
10625                selection.start.column += indent_delta.len;
10626            }
10627            if row == selection.end.row {
10628                selection.end.column += indent_delta.len;
10629                delta_for_end_row = indent_delta.len;
10630            }
10631        }
10632
10633        if selection.start.row == selection.end.row {
10634            delta_for_start_row + delta_for_end_row
10635        } else {
10636            delta_for_end_row
10637        }
10638    }
10639
10640    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10641        if self.read_only(cx) {
10642            return;
10643        }
10644        if self.mode.is_single_line() {
10645            cx.propagate();
10646            return;
10647        }
10648
10649        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10650        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10651        let selections = self.selections.all::<Point>(&display_map);
10652        let mut deletion_ranges = Vec::new();
10653        let mut last_outdent = None;
10654        {
10655            let buffer = self.buffer.read(cx);
10656            let snapshot = buffer.snapshot(cx);
10657            for selection in &selections {
10658                let settings = buffer.language_settings_at(selection.start, cx);
10659                let tab_size = settings.tab_size.get();
10660                let mut rows = selection.spanned_rows(false, &display_map);
10661
10662                // Avoid re-outdenting a row that has already been outdented by a
10663                // previous selection.
10664                if let Some(last_row) = last_outdent
10665                    && last_row == rows.start
10666                {
10667                    rows.start = rows.start.next_row();
10668                }
10669                let has_multiple_rows = rows.len() > 1;
10670                for row in rows.iter_rows() {
10671                    let indent_size = snapshot.indent_size_for_line(row);
10672                    if indent_size.len > 0 {
10673                        let deletion_len = match indent_size.kind {
10674                            IndentKind::Space => {
10675                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10676                                if columns_to_prev_tab_stop == 0 {
10677                                    tab_size
10678                                } else {
10679                                    columns_to_prev_tab_stop
10680                                }
10681                            }
10682                            IndentKind::Tab => 1,
10683                        };
10684                        let start = if has_multiple_rows
10685                            || deletion_len > selection.start.column
10686                            || indent_size.len < selection.start.column
10687                        {
10688                            0
10689                        } else {
10690                            selection.start.column - deletion_len
10691                        };
10692                        deletion_ranges.push(
10693                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10694                        );
10695                        last_outdent = Some(row);
10696                    }
10697                }
10698            }
10699        }
10700
10701        self.transact(window, cx, |this, window, cx| {
10702            this.buffer.update(cx, |buffer, cx| {
10703                let empty_str: Arc<str> = Arc::default();
10704                buffer.edit(
10705                    deletion_ranges
10706                        .into_iter()
10707                        .map(|range| (range, empty_str.clone())),
10708                    None,
10709                    cx,
10710                );
10711            });
10712            let selections = this
10713                .selections
10714                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10715            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10716        });
10717    }
10718
10719    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10720        if self.read_only(cx) {
10721            return;
10722        }
10723        if self.mode.is_single_line() {
10724            cx.propagate();
10725            return;
10726        }
10727
10728        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10729        let selections = self
10730            .selections
10731            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10732            .into_iter()
10733            .map(|s| s.range());
10734
10735        self.transact(window, cx, |this, window, cx| {
10736            this.buffer.update(cx, |buffer, cx| {
10737                buffer.autoindent_ranges(selections, cx);
10738            });
10739            let selections = this
10740                .selections
10741                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10742            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10743        });
10744    }
10745
10746    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10747        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10748        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10749        let selections = self.selections.all::<Point>(&display_map);
10750
10751        let mut new_cursors = Vec::new();
10752        let mut edit_ranges = Vec::new();
10753        let mut selections = selections.iter().peekable();
10754        while let Some(selection) = selections.next() {
10755            let mut rows = selection.spanned_rows(false, &display_map);
10756
10757            // Accumulate contiguous regions of rows that we want to delete.
10758            while let Some(next_selection) = selections.peek() {
10759                let next_rows = next_selection.spanned_rows(false, &display_map);
10760                if next_rows.start <= rows.end {
10761                    rows.end = next_rows.end;
10762                    selections.next().unwrap();
10763                } else {
10764                    break;
10765                }
10766            }
10767
10768            let buffer = display_map.buffer_snapshot();
10769            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10770            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10771                // If there's a line after the range, delete the \n from the end of the row range
10772                (
10773                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10774                    rows.end,
10775                )
10776            } else {
10777                // If there isn't a line after the range, delete the \n from the line before the
10778                // start of the row range
10779                edit_start = edit_start.saturating_sub_usize(1);
10780                (buffer.len(), rows.start.previous_row())
10781            };
10782
10783            let text_layout_details = self.text_layout_details(window);
10784            let x = display_map.x_for_display_point(
10785                selection.head().to_display_point(&display_map),
10786                &text_layout_details,
10787            );
10788            let row = Point::new(target_row.0, 0)
10789                .to_display_point(&display_map)
10790                .row();
10791            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10792
10793            new_cursors.push((
10794                selection.id,
10795                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10796                SelectionGoal::None,
10797            ));
10798            edit_ranges.push(edit_start..edit_end);
10799        }
10800
10801        self.transact(window, cx, |this, window, cx| {
10802            let buffer = this.buffer.update(cx, |buffer, cx| {
10803                let empty_str: Arc<str> = Arc::default();
10804                buffer.edit(
10805                    edit_ranges
10806                        .into_iter()
10807                        .map(|range| (range, empty_str.clone())),
10808                    None,
10809                    cx,
10810                );
10811                buffer.snapshot(cx)
10812            });
10813            let new_selections = new_cursors
10814                .into_iter()
10815                .map(|(id, cursor, goal)| {
10816                    let cursor = cursor.to_point(&buffer);
10817                    Selection {
10818                        id,
10819                        start: cursor,
10820                        end: cursor,
10821                        reversed: false,
10822                        goal,
10823                    }
10824                })
10825                .collect();
10826
10827            this.change_selections(Default::default(), window, cx, |s| {
10828                s.select(new_selections);
10829            });
10830        });
10831    }
10832
10833    pub fn join_lines_impl(
10834        &mut self,
10835        insert_whitespace: bool,
10836        window: &mut Window,
10837        cx: &mut Context<Self>,
10838    ) {
10839        if self.read_only(cx) {
10840            return;
10841        }
10842        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10843        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10844            let start = MultiBufferRow(selection.start.row);
10845            // Treat single line selections as if they include the next line. Otherwise this action
10846            // would do nothing for single line selections individual cursors.
10847            let end = if selection.start.row == selection.end.row {
10848                MultiBufferRow(selection.start.row + 1)
10849            } else {
10850                MultiBufferRow(selection.end.row)
10851            };
10852
10853            if let Some(last_row_range) = row_ranges.last_mut()
10854                && start <= last_row_range.end
10855            {
10856                last_row_range.end = end;
10857                continue;
10858            }
10859            row_ranges.push(start..end);
10860        }
10861
10862        let snapshot = self.buffer.read(cx).snapshot(cx);
10863        let mut cursor_positions = Vec::new();
10864        for row_range in &row_ranges {
10865            let anchor = snapshot.anchor_before(Point::new(
10866                row_range.end.previous_row().0,
10867                snapshot.line_len(row_range.end.previous_row()),
10868            ));
10869            cursor_positions.push(anchor..anchor);
10870        }
10871
10872        self.transact(window, cx, |this, window, cx| {
10873            for row_range in row_ranges.into_iter().rev() {
10874                for row in row_range.iter_rows().rev() {
10875                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10876                    let next_line_row = row.next_row();
10877                    let indent = snapshot.indent_size_for_line(next_line_row);
10878                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10879
10880                    let replace =
10881                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10882                            " "
10883                        } else {
10884                            ""
10885                        };
10886
10887                    this.buffer.update(cx, |buffer, cx| {
10888                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10889                    });
10890                }
10891            }
10892
10893            this.change_selections(Default::default(), window, cx, |s| {
10894                s.select_anchor_ranges(cursor_positions)
10895            });
10896        });
10897    }
10898
10899    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10900        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10901        self.join_lines_impl(true, window, cx);
10902    }
10903
10904    pub fn sort_lines_case_sensitive(
10905        &mut self,
10906        _: &SortLinesCaseSensitive,
10907        window: &mut Window,
10908        cx: &mut Context<Self>,
10909    ) {
10910        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10911    }
10912
10913    pub fn sort_lines_by_length(
10914        &mut self,
10915        _: &SortLinesByLength,
10916        window: &mut Window,
10917        cx: &mut Context<Self>,
10918    ) {
10919        self.manipulate_immutable_lines(window, cx, |lines| {
10920            lines.sort_by_key(|&line| line.chars().count())
10921        })
10922    }
10923
10924    pub fn sort_lines_case_insensitive(
10925        &mut self,
10926        _: &SortLinesCaseInsensitive,
10927        window: &mut Window,
10928        cx: &mut Context<Self>,
10929    ) {
10930        self.manipulate_immutable_lines(window, cx, |lines| {
10931            lines.sort_by_key(|line| line.to_lowercase())
10932        })
10933    }
10934
10935    pub fn unique_lines_case_insensitive(
10936        &mut self,
10937        _: &UniqueLinesCaseInsensitive,
10938        window: &mut Window,
10939        cx: &mut Context<Self>,
10940    ) {
10941        self.manipulate_immutable_lines(window, cx, |lines| {
10942            let mut seen = HashSet::default();
10943            lines.retain(|line| seen.insert(line.to_lowercase()));
10944        })
10945    }
10946
10947    pub fn unique_lines_case_sensitive(
10948        &mut self,
10949        _: &UniqueLinesCaseSensitive,
10950        window: &mut Window,
10951        cx: &mut Context<Self>,
10952    ) {
10953        self.manipulate_immutable_lines(window, cx, |lines| {
10954            let mut seen = HashSet::default();
10955            lines.retain(|line| seen.insert(*line));
10956        })
10957    }
10958
10959    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10960        let snapshot = self.buffer.read(cx).snapshot(cx);
10961        for selection in self.selections.disjoint_anchors_arc().iter() {
10962            if snapshot
10963                .language_at(selection.start)
10964                .and_then(|lang| lang.config().wrap_characters.as_ref())
10965                .is_some()
10966            {
10967                return true;
10968            }
10969        }
10970        false
10971    }
10972
10973    fn wrap_selections_in_tag(
10974        &mut self,
10975        _: &WrapSelectionsInTag,
10976        window: &mut Window,
10977        cx: &mut Context<Self>,
10978    ) {
10979        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10980
10981        let snapshot = self.buffer.read(cx).snapshot(cx);
10982
10983        let mut edits = Vec::new();
10984        let mut boundaries = Vec::new();
10985
10986        for selection in self
10987            .selections
10988            .all_adjusted(&self.display_snapshot(cx))
10989            .iter()
10990        {
10991            let Some(wrap_config) = snapshot
10992                .language_at(selection.start)
10993                .and_then(|lang| lang.config().wrap_characters.clone())
10994            else {
10995                continue;
10996            };
10997
10998            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10999            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11000
11001            let start_before = snapshot.anchor_before(selection.start);
11002            let end_after = snapshot.anchor_after(selection.end);
11003
11004            edits.push((start_before..start_before, open_tag));
11005            edits.push((end_after..end_after, close_tag));
11006
11007            boundaries.push((
11008                start_before,
11009                end_after,
11010                wrap_config.start_prefix.len(),
11011                wrap_config.end_suffix.len(),
11012            ));
11013        }
11014
11015        if edits.is_empty() {
11016            return;
11017        }
11018
11019        self.transact(window, cx, |this, window, cx| {
11020            let buffer = this.buffer.update(cx, |buffer, cx| {
11021                buffer.edit(edits, None, cx);
11022                buffer.snapshot(cx)
11023            });
11024
11025            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11026            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11027                boundaries.into_iter()
11028            {
11029                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11030                let close_offset = end_after
11031                    .to_offset(&buffer)
11032                    .saturating_sub_usize(end_suffix_len);
11033                new_selections.push(open_offset..open_offset);
11034                new_selections.push(close_offset..close_offset);
11035            }
11036
11037            this.change_selections(Default::default(), window, cx, |s| {
11038                s.select_ranges(new_selections);
11039            });
11040
11041            this.request_autoscroll(Autoscroll::fit(), cx);
11042        });
11043    }
11044
11045    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11046        let Some(project) = self.project.clone() else {
11047            return;
11048        };
11049        self.reload(project, window, cx)
11050            .detach_and_notify_err(window, cx);
11051    }
11052
11053    pub fn restore_file(
11054        &mut self,
11055        _: &::git::RestoreFile,
11056        window: &mut Window,
11057        cx: &mut Context<Self>,
11058    ) {
11059        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11060        let mut buffer_ids = HashSet::default();
11061        let snapshot = self.buffer().read(cx).snapshot(cx);
11062        for selection in self
11063            .selections
11064            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11065        {
11066            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11067        }
11068
11069        let buffer = self.buffer().read(cx);
11070        let ranges = buffer_ids
11071            .into_iter()
11072            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11073            .collect::<Vec<_>>();
11074
11075        self.restore_hunks_in_ranges(ranges, window, cx);
11076    }
11077
11078    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11079        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11080        let selections = self
11081            .selections
11082            .all(&self.display_snapshot(cx))
11083            .into_iter()
11084            .map(|s| s.range())
11085            .collect();
11086        self.restore_hunks_in_ranges(selections, window, cx);
11087    }
11088
11089    pub fn restore_hunks_in_ranges(
11090        &mut self,
11091        ranges: Vec<Range<Point>>,
11092        window: &mut Window,
11093        cx: &mut Context<Editor>,
11094    ) {
11095        let mut revert_changes = HashMap::default();
11096        let chunk_by = self
11097            .snapshot(window, cx)
11098            .hunks_for_ranges(ranges)
11099            .into_iter()
11100            .chunk_by(|hunk| hunk.buffer_id);
11101        for (buffer_id, hunks) in &chunk_by {
11102            let hunks = hunks.collect::<Vec<_>>();
11103            for hunk in &hunks {
11104                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11105            }
11106            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11107        }
11108        drop(chunk_by);
11109        if !revert_changes.is_empty() {
11110            self.transact(window, cx, |editor, window, cx| {
11111                editor.restore(revert_changes, window, cx);
11112            });
11113        }
11114    }
11115
11116    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11117        if let Some(status) = self
11118            .addons
11119            .iter()
11120            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11121        {
11122            return Some(status);
11123        }
11124        self.project
11125            .as_ref()?
11126            .read(cx)
11127            .status_for_buffer_id(buffer_id, cx)
11128    }
11129
11130    pub fn open_active_item_in_terminal(
11131        &mut self,
11132        _: &OpenInTerminal,
11133        window: &mut Window,
11134        cx: &mut Context<Self>,
11135    ) {
11136        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11137            let project_path = buffer.read(cx).project_path(cx)?;
11138            let project = self.project()?.read(cx);
11139            let entry = project.entry_for_path(&project_path, cx)?;
11140            let parent = match &entry.canonical_path {
11141                Some(canonical_path) => canonical_path.to_path_buf(),
11142                None => project.absolute_path(&project_path, cx)?,
11143            }
11144            .parent()?
11145            .to_path_buf();
11146            Some(parent)
11147        }) {
11148            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11149        }
11150    }
11151
11152    fn set_breakpoint_context_menu(
11153        &mut self,
11154        display_row: DisplayRow,
11155        position: Option<Anchor>,
11156        clicked_point: gpui::Point<Pixels>,
11157        window: &mut Window,
11158        cx: &mut Context<Self>,
11159    ) {
11160        let source = self
11161            .buffer
11162            .read(cx)
11163            .snapshot(cx)
11164            .anchor_before(Point::new(display_row.0, 0u32));
11165
11166        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11167
11168        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11169            self,
11170            source,
11171            clicked_point,
11172            context_menu,
11173            window,
11174            cx,
11175        );
11176    }
11177
11178    fn add_edit_breakpoint_block(
11179        &mut self,
11180        anchor: Anchor,
11181        breakpoint: &Breakpoint,
11182        edit_action: BreakpointPromptEditAction,
11183        window: &mut Window,
11184        cx: &mut Context<Self>,
11185    ) {
11186        let weak_editor = cx.weak_entity();
11187        let bp_prompt = cx.new(|cx| {
11188            BreakpointPromptEditor::new(
11189                weak_editor,
11190                anchor,
11191                breakpoint.clone(),
11192                edit_action,
11193                window,
11194                cx,
11195            )
11196        });
11197
11198        let height = bp_prompt.update(cx, |this, cx| {
11199            this.prompt
11200                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11201        });
11202        let cloned_prompt = bp_prompt.clone();
11203        let blocks = vec![BlockProperties {
11204            style: BlockStyle::Sticky,
11205            placement: BlockPlacement::Above(anchor),
11206            height: Some(height),
11207            render: Arc::new(move |cx| {
11208                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11209                cloned_prompt.clone().into_any_element()
11210            }),
11211            priority: 0,
11212        }];
11213
11214        let focus_handle = bp_prompt.focus_handle(cx);
11215        window.focus(&focus_handle);
11216
11217        let block_ids = self.insert_blocks(blocks, None, cx);
11218        bp_prompt.update(cx, |prompt, _| {
11219            prompt.add_block_ids(block_ids);
11220        });
11221    }
11222
11223    pub(crate) fn breakpoint_at_row(
11224        &self,
11225        row: u32,
11226        window: &mut Window,
11227        cx: &mut Context<Self>,
11228    ) -> Option<(Anchor, Breakpoint)> {
11229        let snapshot = self.snapshot(window, cx);
11230        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11231
11232        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11233    }
11234
11235    pub(crate) fn breakpoint_at_anchor(
11236        &self,
11237        breakpoint_position: Anchor,
11238        snapshot: &EditorSnapshot,
11239        cx: &mut Context<Self>,
11240    ) -> Option<(Anchor, Breakpoint)> {
11241        let buffer = self
11242            .buffer
11243            .read(cx)
11244            .buffer_for_anchor(breakpoint_position, cx)?;
11245
11246        let enclosing_excerpt = breakpoint_position.excerpt_id;
11247        let buffer_snapshot = buffer.read(cx).snapshot();
11248
11249        let row = buffer_snapshot
11250            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11251            .row;
11252
11253        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11254        let anchor_end = snapshot
11255            .buffer_snapshot()
11256            .anchor_after(Point::new(row, line_len));
11257
11258        self.breakpoint_store
11259            .as_ref()?
11260            .read_with(cx, |breakpoint_store, cx| {
11261                breakpoint_store
11262                    .breakpoints(
11263                        &buffer,
11264                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11265                        &buffer_snapshot,
11266                        cx,
11267                    )
11268                    .next()
11269                    .and_then(|(bp, _)| {
11270                        let breakpoint_row = buffer_snapshot
11271                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11272                            .row;
11273
11274                        if breakpoint_row == row {
11275                            snapshot
11276                                .buffer_snapshot()
11277                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11278                                .map(|position| (position, bp.bp.clone()))
11279                        } else {
11280                            None
11281                        }
11282                    })
11283            })
11284    }
11285
11286    pub fn edit_log_breakpoint(
11287        &mut self,
11288        _: &EditLogBreakpoint,
11289        window: &mut Window,
11290        cx: &mut Context<Self>,
11291    ) {
11292        if self.breakpoint_store.is_none() {
11293            return;
11294        }
11295
11296        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11297            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11298                message: None,
11299                state: BreakpointState::Enabled,
11300                condition: None,
11301                hit_condition: None,
11302            });
11303
11304            self.add_edit_breakpoint_block(
11305                anchor,
11306                &breakpoint,
11307                BreakpointPromptEditAction::Log,
11308                window,
11309                cx,
11310            );
11311        }
11312    }
11313
11314    fn breakpoints_at_cursors(
11315        &self,
11316        window: &mut Window,
11317        cx: &mut Context<Self>,
11318    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11319        let snapshot = self.snapshot(window, cx);
11320        let cursors = self
11321            .selections
11322            .disjoint_anchors_arc()
11323            .iter()
11324            .map(|selection| {
11325                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11326
11327                let breakpoint_position = self
11328                    .breakpoint_at_row(cursor_position.row, window, cx)
11329                    .map(|bp| bp.0)
11330                    .unwrap_or_else(|| {
11331                        snapshot
11332                            .display_snapshot
11333                            .buffer_snapshot()
11334                            .anchor_after(Point::new(cursor_position.row, 0))
11335                    });
11336
11337                let breakpoint = self
11338                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11339                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11340
11341                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11342            })
11343            // 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.
11344            .collect::<HashMap<Anchor, _>>();
11345
11346        cursors.into_iter().collect()
11347    }
11348
11349    pub fn enable_breakpoint(
11350        &mut self,
11351        _: &crate::actions::EnableBreakpoint,
11352        window: &mut Window,
11353        cx: &mut Context<Self>,
11354    ) {
11355        if self.breakpoint_store.is_none() {
11356            return;
11357        }
11358
11359        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11360            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11361                continue;
11362            };
11363            self.edit_breakpoint_at_anchor(
11364                anchor,
11365                breakpoint,
11366                BreakpointEditAction::InvertState,
11367                cx,
11368            );
11369        }
11370    }
11371
11372    pub fn disable_breakpoint(
11373        &mut self,
11374        _: &crate::actions::DisableBreakpoint,
11375        window: &mut Window,
11376        cx: &mut Context<Self>,
11377    ) {
11378        if self.breakpoint_store.is_none() {
11379            return;
11380        }
11381
11382        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11383            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11384                continue;
11385            };
11386            self.edit_breakpoint_at_anchor(
11387                anchor,
11388                breakpoint,
11389                BreakpointEditAction::InvertState,
11390                cx,
11391            );
11392        }
11393    }
11394
11395    pub fn toggle_breakpoint(
11396        &mut self,
11397        _: &crate::actions::ToggleBreakpoint,
11398        window: &mut Window,
11399        cx: &mut Context<Self>,
11400    ) {
11401        if self.breakpoint_store.is_none() {
11402            return;
11403        }
11404
11405        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11406            if let Some(breakpoint) = breakpoint {
11407                self.edit_breakpoint_at_anchor(
11408                    anchor,
11409                    breakpoint,
11410                    BreakpointEditAction::Toggle,
11411                    cx,
11412                );
11413            } else {
11414                self.edit_breakpoint_at_anchor(
11415                    anchor,
11416                    Breakpoint::new_standard(),
11417                    BreakpointEditAction::Toggle,
11418                    cx,
11419                );
11420            }
11421        }
11422    }
11423
11424    pub fn edit_breakpoint_at_anchor(
11425        &mut self,
11426        breakpoint_position: Anchor,
11427        breakpoint: Breakpoint,
11428        edit_action: BreakpointEditAction,
11429        cx: &mut Context<Self>,
11430    ) {
11431        let Some(breakpoint_store) = &self.breakpoint_store else {
11432            return;
11433        };
11434
11435        let Some(buffer) = self
11436            .buffer
11437            .read(cx)
11438            .buffer_for_anchor(breakpoint_position, cx)
11439        else {
11440            return;
11441        };
11442
11443        breakpoint_store.update(cx, |breakpoint_store, cx| {
11444            breakpoint_store.toggle_breakpoint(
11445                buffer,
11446                BreakpointWithPosition {
11447                    position: breakpoint_position.text_anchor,
11448                    bp: breakpoint,
11449                },
11450                edit_action,
11451                cx,
11452            );
11453        });
11454
11455        cx.notify();
11456    }
11457
11458    #[cfg(any(test, feature = "test-support"))]
11459    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11460        self.breakpoint_store.clone()
11461    }
11462
11463    pub fn prepare_restore_change(
11464        &self,
11465        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11466        hunk: &MultiBufferDiffHunk,
11467        cx: &mut App,
11468    ) -> Option<()> {
11469        if hunk.is_created_file() {
11470            return None;
11471        }
11472        let buffer = self.buffer.read(cx);
11473        let diff = buffer.diff_for(hunk.buffer_id)?;
11474        let buffer = buffer.buffer(hunk.buffer_id)?;
11475        let buffer = buffer.read(cx);
11476        let original_text = diff
11477            .read(cx)
11478            .base_text()
11479            .as_rope()
11480            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11481        let buffer_snapshot = buffer.snapshot();
11482        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11483        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11484            probe
11485                .0
11486                .start
11487                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11488                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11489        }) {
11490            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11491            Some(())
11492        } else {
11493            None
11494        }
11495    }
11496
11497    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11498        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11499    }
11500
11501    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11502        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11503    }
11504
11505    pub fn rotate_selections_forward(
11506        &mut self,
11507        _: &RotateSelectionsForward,
11508        window: &mut Window,
11509        cx: &mut Context<Self>,
11510    ) {
11511        self.rotate_selections(window, cx, false)
11512    }
11513
11514    pub fn rotate_selections_backward(
11515        &mut self,
11516        _: &RotateSelectionsBackward,
11517        window: &mut Window,
11518        cx: &mut Context<Self>,
11519    ) {
11520        self.rotate_selections(window, cx, true)
11521    }
11522
11523    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11524        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11525        let display_snapshot = self.display_snapshot(cx);
11526        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11527
11528        if selections.len() < 2 {
11529            return;
11530        }
11531
11532        let (edits, new_selections) = {
11533            let buffer = self.buffer.read(cx).read(cx);
11534            let has_selections = selections.iter().any(|s| !s.is_empty());
11535            if has_selections {
11536                let mut selected_texts: Vec<String> = selections
11537                    .iter()
11538                    .map(|selection| {
11539                        buffer
11540                            .text_for_range(selection.start..selection.end)
11541                            .collect()
11542                    })
11543                    .collect();
11544
11545                if reverse {
11546                    selected_texts.rotate_left(1);
11547                } else {
11548                    selected_texts.rotate_right(1);
11549                }
11550
11551                let mut offset_delta: i64 = 0;
11552                let mut new_selections = Vec::new();
11553                let edits: Vec<_> = selections
11554                    .iter()
11555                    .zip(selected_texts.iter())
11556                    .map(|(selection, new_text)| {
11557                        let old_len = (selection.end.0 - selection.start.0) as i64;
11558                        let new_len = new_text.len() as i64;
11559                        let adjusted_start =
11560                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11561                        let adjusted_end =
11562                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11563
11564                        new_selections.push(Selection {
11565                            id: selection.id,
11566                            start: adjusted_start,
11567                            end: adjusted_end,
11568                            reversed: selection.reversed,
11569                            goal: selection.goal,
11570                        });
11571
11572                        offset_delta += new_len - old_len;
11573                        (selection.start..selection.end, new_text.clone())
11574                    })
11575                    .collect();
11576                (edits, new_selections)
11577            } else {
11578                let mut all_rows: Vec<u32> = selections
11579                    .iter()
11580                    .map(|selection| buffer.offset_to_point(selection.start).row)
11581                    .collect();
11582                all_rows.sort_unstable();
11583                all_rows.dedup();
11584
11585                if all_rows.len() < 2 {
11586                    return;
11587                }
11588
11589                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11590                    .iter()
11591                    .map(|&row| {
11592                        let start = Point::new(row, 0);
11593                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11594                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11595                    })
11596                    .collect();
11597
11598                let mut line_texts: Vec<String> = line_ranges
11599                    .iter()
11600                    .map(|range| buffer.text_for_range(range.clone()).collect())
11601                    .collect();
11602
11603                if reverse {
11604                    line_texts.rotate_left(1);
11605                } else {
11606                    line_texts.rotate_right(1);
11607                }
11608
11609                let edits = line_ranges
11610                    .iter()
11611                    .zip(line_texts.iter())
11612                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11613                    .collect();
11614
11615                let num_rows = all_rows.len();
11616                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11617                    .iter()
11618                    .enumerate()
11619                    .map(|(i, &row)| (row, i))
11620                    .collect();
11621
11622                // Compute new line start offsets after rotation (handles CRLF)
11623                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11624                let first_line_start = line_ranges[0].start.0;
11625                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11626                for text in line_texts.iter().take(num_rows - 1) {
11627                    let prev_start = *new_line_starts.last().unwrap();
11628                    new_line_starts.push(prev_start + text.len() + newline_len);
11629                }
11630
11631                let new_selections = selections
11632                    .iter()
11633                    .map(|selection| {
11634                        let point = buffer.offset_to_point(selection.start);
11635                        let old_index = row_to_index[&point.row];
11636                        let new_index = if reverse {
11637                            (old_index + num_rows - 1) % num_rows
11638                        } else {
11639                            (old_index + 1) % num_rows
11640                        };
11641                        let new_offset =
11642                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11643                        Selection {
11644                            id: selection.id,
11645                            start: new_offset,
11646                            end: new_offset,
11647                            reversed: selection.reversed,
11648                            goal: selection.goal,
11649                        }
11650                    })
11651                    .collect();
11652
11653                (edits, new_selections)
11654            }
11655        };
11656
11657        self.transact(window, cx, |this, window, cx| {
11658            this.buffer.update(cx, |buffer, cx| {
11659                buffer.edit(edits, None, cx);
11660            });
11661            this.change_selections(Default::default(), window, cx, |s| {
11662                s.select(new_selections);
11663            });
11664        });
11665    }
11666
11667    fn manipulate_lines<M>(
11668        &mut self,
11669        window: &mut Window,
11670        cx: &mut Context<Self>,
11671        mut manipulate: M,
11672    ) where
11673        M: FnMut(&str) -> LineManipulationResult,
11674    {
11675        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11676
11677        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11678        let buffer = self.buffer.read(cx).snapshot(cx);
11679
11680        let mut edits = Vec::new();
11681
11682        let selections = self.selections.all::<Point>(&display_map);
11683        let mut selections = selections.iter().peekable();
11684        let mut contiguous_row_selections = Vec::new();
11685        let mut new_selections = Vec::new();
11686        let mut added_lines = 0;
11687        let mut removed_lines = 0;
11688
11689        while let Some(selection) = selections.next() {
11690            let (start_row, end_row) = consume_contiguous_rows(
11691                &mut contiguous_row_selections,
11692                selection,
11693                &display_map,
11694                &mut selections,
11695            );
11696
11697            let start_point = Point::new(start_row.0, 0);
11698            let end_point = Point::new(
11699                end_row.previous_row().0,
11700                buffer.line_len(end_row.previous_row()),
11701            );
11702            let text = buffer
11703                .text_for_range(start_point..end_point)
11704                .collect::<String>();
11705
11706            let LineManipulationResult {
11707                new_text,
11708                line_count_before,
11709                line_count_after,
11710            } = manipulate(&text);
11711
11712            edits.push((start_point..end_point, new_text));
11713
11714            // Selections must change based on added and removed line count
11715            let start_row =
11716                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11717            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11718            new_selections.push(Selection {
11719                id: selection.id,
11720                start: start_row,
11721                end: end_row,
11722                goal: SelectionGoal::None,
11723                reversed: selection.reversed,
11724            });
11725
11726            if line_count_after > line_count_before {
11727                added_lines += line_count_after - line_count_before;
11728            } else if line_count_before > line_count_after {
11729                removed_lines += line_count_before - line_count_after;
11730            }
11731        }
11732
11733        self.transact(window, cx, |this, window, cx| {
11734            let buffer = this.buffer.update(cx, |buffer, cx| {
11735                buffer.edit(edits, None, cx);
11736                buffer.snapshot(cx)
11737            });
11738
11739            // Recalculate offsets on newly edited buffer
11740            let new_selections = new_selections
11741                .iter()
11742                .map(|s| {
11743                    let start_point = Point::new(s.start.0, 0);
11744                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11745                    Selection {
11746                        id: s.id,
11747                        start: buffer.point_to_offset(start_point),
11748                        end: buffer.point_to_offset(end_point),
11749                        goal: s.goal,
11750                        reversed: s.reversed,
11751                    }
11752                })
11753                .collect();
11754
11755            this.change_selections(Default::default(), window, cx, |s| {
11756                s.select(new_selections);
11757            });
11758
11759            this.request_autoscroll(Autoscroll::fit(), cx);
11760        });
11761    }
11762
11763    fn manipulate_immutable_lines<Fn>(
11764        &mut self,
11765        window: &mut Window,
11766        cx: &mut Context<Self>,
11767        mut callback: Fn,
11768    ) where
11769        Fn: FnMut(&mut Vec<&str>),
11770    {
11771        self.manipulate_lines(window, cx, |text| {
11772            let mut lines: Vec<&str> = text.split('\n').collect();
11773            let line_count_before = lines.len();
11774
11775            callback(&mut lines);
11776
11777            LineManipulationResult {
11778                new_text: lines.join("\n"),
11779                line_count_before,
11780                line_count_after: lines.len(),
11781            }
11782        });
11783    }
11784
11785    fn manipulate_mutable_lines<Fn>(
11786        &mut self,
11787        window: &mut Window,
11788        cx: &mut Context<Self>,
11789        mut callback: Fn,
11790    ) where
11791        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11792    {
11793        self.manipulate_lines(window, cx, |text| {
11794            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11795            let line_count_before = lines.len();
11796
11797            callback(&mut lines);
11798
11799            LineManipulationResult {
11800                new_text: lines.join("\n"),
11801                line_count_before,
11802                line_count_after: lines.len(),
11803            }
11804        });
11805    }
11806
11807    pub fn convert_indentation_to_spaces(
11808        &mut self,
11809        _: &ConvertIndentationToSpaces,
11810        window: &mut Window,
11811        cx: &mut Context<Self>,
11812    ) {
11813        let settings = self.buffer.read(cx).language_settings(cx);
11814        let tab_size = settings.tab_size.get() as usize;
11815
11816        self.manipulate_mutable_lines(window, cx, |lines| {
11817            // Allocates a reasonably sized scratch buffer once for the whole loop
11818            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11819            // Avoids recomputing spaces that could be inserted many times
11820            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11821                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11822                .collect();
11823
11824            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11825                let mut chars = line.as_ref().chars();
11826                let mut col = 0;
11827                let mut changed = false;
11828
11829                for ch in chars.by_ref() {
11830                    match ch {
11831                        ' ' => {
11832                            reindented_line.push(' ');
11833                            col += 1;
11834                        }
11835                        '\t' => {
11836                            // \t are converted to spaces depending on the current column
11837                            let spaces_len = tab_size - (col % tab_size);
11838                            reindented_line.extend(&space_cache[spaces_len - 1]);
11839                            col += spaces_len;
11840                            changed = true;
11841                        }
11842                        _ => {
11843                            // If we dont append before break, the character is consumed
11844                            reindented_line.push(ch);
11845                            break;
11846                        }
11847                    }
11848                }
11849
11850                if !changed {
11851                    reindented_line.clear();
11852                    continue;
11853                }
11854                // Append the rest of the line and replace old reference with new one
11855                reindented_line.extend(chars);
11856                *line = Cow::Owned(reindented_line.clone());
11857                reindented_line.clear();
11858            }
11859        });
11860    }
11861
11862    pub fn convert_indentation_to_tabs(
11863        &mut self,
11864        _: &ConvertIndentationToTabs,
11865        window: &mut Window,
11866        cx: &mut Context<Self>,
11867    ) {
11868        let settings = self.buffer.read(cx).language_settings(cx);
11869        let tab_size = settings.tab_size.get() as usize;
11870
11871        self.manipulate_mutable_lines(window, cx, |lines| {
11872            // Allocates a reasonably sized buffer once for the whole loop
11873            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11874            // Avoids recomputing spaces that could be inserted many times
11875            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11876                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11877                .collect();
11878
11879            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11880                let mut chars = line.chars();
11881                let mut spaces_count = 0;
11882                let mut first_non_indent_char = None;
11883                let mut changed = false;
11884
11885                for ch in chars.by_ref() {
11886                    match ch {
11887                        ' ' => {
11888                            // Keep track of spaces. Append \t when we reach tab_size
11889                            spaces_count += 1;
11890                            changed = true;
11891                            if spaces_count == tab_size {
11892                                reindented_line.push('\t');
11893                                spaces_count = 0;
11894                            }
11895                        }
11896                        '\t' => {
11897                            reindented_line.push('\t');
11898                            spaces_count = 0;
11899                        }
11900                        _ => {
11901                            // Dont append it yet, we might have remaining spaces
11902                            first_non_indent_char = Some(ch);
11903                            break;
11904                        }
11905                    }
11906                }
11907
11908                if !changed {
11909                    reindented_line.clear();
11910                    continue;
11911                }
11912                // Remaining spaces that didn't make a full tab stop
11913                if spaces_count > 0 {
11914                    reindented_line.extend(&space_cache[spaces_count - 1]);
11915                }
11916                // If we consume an extra character that was not indentation, add it back
11917                if let Some(extra_char) = first_non_indent_char {
11918                    reindented_line.push(extra_char);
11919                }
11920                // Append the rest of the line and replace old reference with new one
11921                reindented_line.extend(chars);
11922                *line = Cow::Owned(reindented_line.clone());
11923                reindented_line.clear();
11924            }
11925        });
11926    }
11927
11928    pub fn convert_to_upper_case(
11929        &mut self,
11930        _: &ConvertToUpperCase,
11931        window: &mut Window,
11932        cx: &mut Context<Self>,
11933    ) {
11934        self.manipulate_text(window, cx, |text| text.to_uppercase())
11935    }
11936
11937    pub fn convert_to_lower_case(
11938        &mut self,
11939        _: &ConvertToLowerCase,
11940        window: &mut Window,
11941        cx: &mut Context<Self>,
11942    ) {
11943        self.manipulate_text(window, cx, |text| text.to_lowercase())
11944    }
11945
11946    pub fn convert_to_title_case(
11947        &mut self,
11948        _: &ConvertToTitleCase,
11949        window: &mut Window,
11950        cx: &mut Context<Self>,
11951    ) {
11952        self.manipulate_text(window, cx, |text| {
11953            text.split('\n')
11954                .map(|line| line.to_case(Case::Title))
11955                .join("\n")
11956        })
11957    }
11958
11959    pub fn convert_to_snake_case(
11960        &mut self,
11961        _: &ConvertToSnakeCase,
11962        window: &mut Window,
11963        cx: &mut Context<Self>,
11964    ) {
11965        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11966    }
11967
11968    pub fn convert_to_kebab_case(
11969        &mut self,
11970        _: &ConvertToKebabCase,
11971        window: &mut Window,
11972        cx: &mut Context<Self>,
11973    ) {
11974        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11975    }
11976
11977    pub fn convert_to_upper_camel_case(
11978        &mut self,
11979        _: &ConvertToUpperCamelCase,
11980        window: &mut Window,
11981        cx: &mut Context<Self>,
11982    ) {
11983        self.manipulate_text(window, cx, |text| {
11984            text.split('\n')
11985                .map(|line| line.to_case(Case::UpperCamel))
11986                .join("\n")
11987        })
11988    }
11989
11990    pub fn convert_to_lower_camel_case(
11991        &mut self,
11992        _: &ConvertToLowerCamelCase,
11993        window: &mut Window,
11994        cx: &mut Context<Self>,
11995    ) {
11996        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11997    }
11998
11999    pub fn convert_to_opposite_case(
12000        &mut self,
12001        _: &ConvertToOppositeCase,
12002        window: &mut Window,
12003        cx: &mut Context<Self>,
12004    ) {
12005        self.manipulate_text(window, cx, |text| {
12006            text.chars()
12007                .fold(String::with_capacity(text.len()), |mut t, c| {
12008                    if c.is_uppercase() {
12009                        t.extend(c.to_lowercase());
12010                    } else {
12011                        t.extend(c.to_uppercase());
12012                    }
12013                    t
12014                })
12015        })
12016    }
12017
12018    pub fn convert_to_sentence_case(
12019        &mut self,
12020        _: &ConvertToSentenceCase,
12021        window: &mut Window,
12022        cx: &mut Context<Self>,
12023    ) {
12024        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12025    }
12026
12027    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12028        self.manipulate_text(window, cx, |text| {
12029            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12030            if has_upper_case_characters {
12031                text.to_lowercase()
12032            } else {
12033                text.to_uppercase()
12034            }
12035        })
12036    }
12037
12038    pub fn convert_to_rot13(
12039        &mut self,
12040        _: &ConvertToRot13,
12041        window: &mut Window,
12042        cx: &mut Context<Self>,
12043    ) {
12044        self.manipulate_text(window, cx, |text| {
12045            text.chars()
12046                .map(|c| match c {
12047                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12048                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12049                    _ => c,
12050                })
12051                .collect()
12052        })
12053    }
12054
12055    pub fn convert_to_rot47(
12056        &mut self,
12057        _: &ConvertToRot47,
12058        window: &mut Window,
12059        cx: &mut Context<Self>,
12060    ) {
12061        self.manipulate_text(window, cx, |text| {
12062            text.chars()
12063                .map(|c| {
12064                    let code_point = c as u32;
12065                    if code_point >= 33 && code_point <= 126 {
12066                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12067                    }
12068                    c
12069                })
12070                .collect()
12071        })
12072    }
12073
12074    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12075    where
12076        Fn: FnMut(&str) -> String,
12077    {
12078        let buffer = self.buffer.read(cx).snapshot(cx);
12079
12080        let mut new_selections = Vec::new();
12081        let mut edits = Vec::new();
12082        let mut selection_adjustment = 0isize;
12083
12084        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12085            let selection_is_empty = selection.is_empty();
12086
12087            let (start, end) = if selection_is_empty {
12088                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12089                (word_range.start, word_range.end)
12090            } else {
12091                (
12092                    buffer.point_to_offset(selection.start),
12093                    buffer.point_to_offset(selection.end),
12094                )
12095            };
12096
12097            let text = buffer.text_for_range(start..end).collect::<String>();
12098            let old_length = text.len() as isize;
12099            let text = callback(&text);
12100
12101            new_selections.push(Selection {
12102                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12103                end: MultiBufferOffset(
12104                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12105                ),
12106                goal: SelectionGoal::None,
12107                id: selection.id,
12108                reversed: selection.reversed,
12109            });
12110
12111            selection_adjustment += old_length - text.len() as isize;
12112
12113            edits.push((start..end, text));
12114        }
12115
12116        self.transact(window, cx, |this, window, cx| {
12117            this.buffer.update(cx, |buffer, cx| {
12118                buffer.edit(edits, None, cx);
12119            });
12120
12121            this.change_selections(Default::default(), window, cx, |s| {
12122                s.select(new_selections);
12123            });
12124
12125            this.request_autoscroll(Autoscroll::fit(), cx);
12126        });
12127    }
12128
12129    pub fn move_selection_on_drop(
12130        &mut self,
12131        selection: &Selection<Anchor>,
12132        target: DisplayPoint,
12133        is_cut: bool,
12134        window: &mut Window,
12135        cx: &mut Context<Self>,
12136    ) {
12137        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12138        let buffer = display_map.buffer_snapshot();
12139        let mut edits = Vec::new();
12140        let insert_point = display_map
12141            .clip_point(target, Bias::Left)
12142            .to_point(&display_map);
12143        let text = buffer
12144            .text_for_range(selection.start..selection.end)
12145            .collect::<String>();
12146        if is_cut {
12147            edits.push(((selection.start..selection.end), String::new()));
12148        }
12149        let insert_anchor = buffer.anchor_before(insert_point);
12150        edits.push(((insert_anchor..insert_anchor), text));
12151        let last_edit_start = insert_anchor.bias_left(buffer);
12152        let last_edit_end = insert_anchor.bias_right(buffer);
12153        self.transact(window, cx, |this, window, cx| {
12154            this.buffer.update(cx, |buffer, cx| {
12155                buffer.edit(edits, None, cx);
12156            });
12157            this.change_selections(Default::default(), window, cx, |s| {
12158                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12159            });
12160        });
12161    }
12162
12163    pub fn clear_selection_drag_state(&mut self) {
12164        self.selection_drag_state = SelectionDragState::None;
12165    }
12166
12167    pub fn duplicate(
12168        &mut self,
12169        upwards: bool,
12170        whole_lines: bool,
12171        window: &mut Window,
12172        cx: &mut Context<Self>,
12173    ) {
12174        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12175
12176        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12177        let buffer = display_map.buffer_snapshot();
12178        let selections = self.selections.all::<Point>(&display_map);
12179
12180        let mut edits = Vec::new();
12181        let mut selections_iter = selections.iter().peekable();
12182        while let Some(selection) = selections_iter.next() {
12183            let mut rows = selection.spanned_rows(false, &display_map);
12184            // duplicate line-wise
12185            if whole_lines || selection.start == selection.end {
12186                // Avoid duplicating the same lines twice.
12187                while let Some(next_selection) = selections_iter.peek() {
12188                    let next_rows = next_selection.spanned_rows(false, &display_map);
12189                    if next_rows.start < rows.end {
12190                        rows.end = next_rows.end;
12191                        selections_iter.next().unwrap();
12192                    } else {
12193                        break;
12194                    }
12195                }
12196
12197                // Copy the text from the selected row region and splice it either at the start
12198                // or end of the region.
12199                let start = Point::new(rows.start.0, 0);
12200                let end = Point::new(
12201                    rows.end.previous_row().0,
12202                    buffer.line_len(rows.end.previous_row()),
12203                );
12204
12205                let mut text = buffer.text_for_range(start..end).collect::<String>();
12206
12207                let insert_location = if upwards {
12208                    // When duplicating upward, we need to insert before the current line.
12209                    // If we're on the last line and it doesn't end with a newline,
12210                    // we need to add a newline before the duplicated content.
12211                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12212                        && buffer.max_point().column > 0
12213                        && !text.ends_with('\n');
12214
12215                    if needs_leading_newline {
12216                        text.insert(0, '\n');
12217                        end
12218                    } else {
12219                        text.push('\n');
12220                        Point::new(rows.start.0, 0)
12221                    }
12222                } else {
12223                    text.push('\n');
12224                    start
12225                };
12226                edits.push((insert_location..insert_location, text));
12227            } else {
12228                // duplicate character-wise
12229                let start = selection.start;
12230                let end = selection.end;
12231                let text = buffer.text_for_range(start..end).collect::<String>();
12232                edits.push((selection.end..selection.end, text));
12233            }
12234        }
12235
12236        self.transact(window, cx, |this, window, cx| {
12237            this.buffer.update(cx, |buffer, cx| {
12238                buffer.edit(edits, None, cx);
12239            });
12240
12241            // When duplicating upward with whole lines, move the cursor to the duplicated line
12242            if upwards && whole_lines {
12243                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12244
12245                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12246                    let mut new_ranges = Vec::new();
12247                    let selections = s.all::<Point>(&display_map);
12248                    let mut selections_iter = selections.iter().peekable();
12249
12250                    while let Some(first_selection) = selections_iter.next() {
12251                        // Group contiguous selections together to find the total row span
12252                        let mut group_selections = vec![first_selection];
12253                        let mut rows = first_selection.spanned_rows(false, &display_map);
12254
12255                        while let Some(next_selection) = selections_iter.peek() {
12256                            let next_rows = next_selection.spanned_rows(false, &display_map);
12257                            if next_rows.start < rows.end {
12258                                rows.end = next_rows.end;
12259                                group_selections.push(selections_iter.next().unwrap());
12260                            } else {
12261                                break;
12262                            }
12263                        }
12264
12265                        let row_count = rows.end.0 - rows.start.0;
12266
12267                        // Move all selections in this group up by the total number of duplicated rows
12268                        for selection in group_selections {
12269                            let new_start = Point::new(
12270                                selection.start.row.saturating_sub(row_count),
12271                                selection.start.column,
12272                            );
12273
12274                            let new_end = Point::new(
12275                                selection.end.row.saturating_sub(row_count),
12276                                selection.end.column,
12277                            );
12278
12279                            new_ranges.push(new_start..new_end);
12280                        }
12281                    }
12282
12283                    s.select_ranges(new_ranges);
12284                });
12285            }
12286
12287            this.request_autoscroll(Autoscroll::fit(), cx);
12288        });
12289    }
12290
12291    pub fn duplicate_line_up(
12292        &mut self,
12293        _: &DuplicateLineUp,
12294        window: &mut Window,
12295        cx: &mut Context<Self>,
12296    ) {
12297        self.duplicate(true, true, window, cx);
12298    }
12299
12300    pub fn duplicate_line_down(
12301        &mut self,
12302        _: &DuplicateLineDown,
12303        window: &mut Window,
12304        cx: &mut Context<Self>,
12305    ) {
12306        self.duplicate(false, true, window, cx);
12307    }
12308
12309    pub fn duplicate_selection(
12310        &mut self,
12311        _: &DuplicateSelection,
12312        window: &mut Window,
12313        cx: &mut Context<Self>,
12314    ) {
12315        self.duplicate(false, false, window, cx);
12316    }
12317
12318    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12319        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12320        if self.mode.is_single_line() {
12321            cx.propagate();
12322            return;
12323        }
12324
12325        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12326        let buffer = self.buffer.read(cx).snapshot(cx);
12327
12328        let mut edits = Vec::new();
12329        let mut unfold_ranges = Vec::new();
12330        let mut refold_creases = Vec::new();
12331
12332        let selections = self.selections.all::<Point>(&display_map);
12333        let mut selections = selections.iter().peekable();
12334        let mut contiguous_row_selections = Vec::new();
12335        let mut new_selections = Vec::new();
12336
12337        while let Some(selection) = selections.next() {
12338            // Find all the selections that span a contiguous row range
12339            let (start_row, end_row) = consume_contiguous_rows(
12340                &mut contiguous_row_selections,
12341                selection,
12342                &display_map,
12343                &mut selections,
12344            );
12345
12346            // Move the text spanned by the row range to be before the line preceding the row range
12347            if start_row.0 > 0 {
12348                let range_to_move = Point::new(
12349                    start_row.previous_row().0,
12350                    buffer.line_len(start_row.previous_row()),
12351                )
12352                    ..Point::new(
12353                        end_row.previous_row().0,
12354                        buffer.line_len(end_row.previous_row()),
12355                    );
12356                let insertion_point = display_map
12357                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12358                    .0;
12359
12360                // Don't move lines across excerpts
12361                if buffer
12362                    .excerpt_containing(insertion_point..range_to_move.end)
12363                    .is_some()
12364                {
12365                    let text = buffer
12366                        .text_for_range(range_to_move.clone())
12367                        .flat_map(|s| s.chars())
12368                        .skip(1)
12369                        .chain(['\n'])
12370                        .collect::<String>();
12371
12372                    edits.push((
12373                        buffer.anchor_after(range_to_move.start)
12374                            ..buffer.anchor_before(range_to_move.end),
12375                        String::new(),
12376                    ));
12377                    let insertion_anchor = buffer.anchor_after(insertion_point);
12378                    edits.push((insertion_anchor..insertion_anchor, text));
12379
12380                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12381
12382                    // Move selections up
12383                    new_selections.extend(contiguous_row_selections.drain(..).map(
12384                        |mut selection| {
12385                            selection.start.row -= row_delta;
12386                            selection.end.row -= row_delta;
12387                            selection
12388                        },
12389                    ));
12390
12391                    // Move folds up
12392                    unfold_ranges.push(range_to_move.clone());
12393                    for fold in display_map.folds_in_range(
12394                        buffer.anchor_before(range_to_move.start)
12395                            ..buffer.anchor_after(range_to_move.end),
12396                    ) {
12397                        let mut start = fold.range.start.to_point(&buffer);
12398                        let mut end = fold.range.end.to_point(&buffer);
12399                        start.row -= row_delta;
12400                        end.row -= row_delta;
12401                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12402                    }
12403                }
12404            }
12405
12406            // If we didn't move line(s), preserve the existing selections
12407            new_selections.append(&mut contiguous_row_selections);
12408        }
12409
12410        self.transact(window, cx, |this, window, cx| {
12411            this.unfold_ranges(&unfold_ranges, true, true, cx);
12412            this.buffer.update(cx, |buffer, cx| {
12413                for (range, text) in edits {
12414                    buffer.edit([(range, text)], None, cx);
12415                }
12416            });
12417            this.fold_creases(refold_creases, true, window, cx);
12418            this.change_selections(Default::default(), window, cx, |s| {
12419                s.select(new_selections);
12420            })
12421        });
12422    }
12423
12424    pub fn move_line_down(
12425        &mut self,
12426        _: &MoveLineDown,
12427        window: &mut Window,
12428        cx: &mut Context<Self>,
12429    ) {
12430        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12431        if self.mode.is_single_line() {
12432            cx.propagate();
12433            return;
12434        }
12435
12436        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12437        let buffer = self.buffer.read(cx).snapshot(cx);
12438
12439        let mut edits = Vec::new();
12440        let mut unfold_ranges = Vec::new();
12441        let mut refold_creases = Vec::new();
12442
12443        let selections = self.selections.all::<Point>(&display_map);
12444        let mut selections = selections.iter().peekable();
12445        let mut contiguous_row_selections = Vec::new();
12446        let mut new_selections = Vec::new();
12447
12448        while let Some(selection) = selections.next() {
12449            // Find all the selections that span a contiguous row range
12450            let (start_row, end_row) = consume_contiguous_rows(
12451                &mut contiguous_row_selections,
12452                selection,
12453                &display_map,
12454                &mut selections,
12455            );
12456
12457            // Move the text spanned by the row range to be after the last line of the row range
12458            if end_row.0 <= buffer.max_point().row {
12459                let range_to_move =
12460                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12461                let insertion_point = display_map
12462                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12463                    .0;
12464
12465                // Don't move lines across excerpt boundaries
12466                if buffer
12467                    .excerpt_containing(range_to_move.start..insertion_point)
12468                    .is_some()
12469                {
12470                    let mut text = String::from("\n");
12471                    text.extend(buffer.text_for_range(range_to_move.clone()));
12472                    text.pop(); // Drop trailing newline
12473                    edits.push((
12474                        buffer.anchor_after(range_to_move.start)
12475                            ..buffer.anchor_before(range_to_move.end),
12476                        String::new(),
12477                    ));
12478                    let insertion_anchor = buffer.anchor_after(insertion_point);
12479                    edits.push((insertion_anchor..insertion_anchor, text));
12480
12481                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12482
12483                    // Move selections down
12484                    new_selections.extend(contiguous_row_selections.drain(..).map(
12485                        |mut selection| {
12486                            selection.start.row += row_delta;
12487                            selection.end.row += row_delta;
12488                            selection
12489                        },
12490                    ));
12491
12492                    // Move folds down
12493                    unfold_ranges.push(range_to_move.clone());
12494                    for fold in display_map.folds_in_range(
12495                        buffer.anchor_before(range_to_move.start)
12496                            ..buffer.anchor_after(range_to_move.end),
12497                    ) {
12498                        let mut start = fold.range.start.to_point(&buffer);
12499                        let mut end = fold.range.end.to_point(&buffer);
12500                        start.row += row_delta;
12501                        end.row += row_delta;
12502                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12503                    }
12504                }
12505            }
12506
12507            // If we didn't move line(s), preserve the existing selections
12508            new_selections.append(&mut contiguous_row_selections);
12509        }
12510
12511        self.transact(window, cx, |this, window, cx| {
12512            this.unfold_ranges(&unfold_ranges, true, true, cx);
12513            this.buffer.update(cx, |buffer, cx| {
12514                for (range, text) in edits {
12515                    buffer.edit([(range, text)], None, cx);
12516                }
12517            });
12518            this.fold_creases(refold_creases, true, window, cx);
12519            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12520        });
12521    }
12522
12523    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12524        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12525        let text_layout_details = &self.text_layout_details(window);
12526        self.transact(window, cx, |this, window, cx| {
12527            let edits = this.change_selections(Default::default(), window, cx, |s| {
12528                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12529                s.move_with(|display_map, selection| {
12530                    if !selection.is_empty() {
12531                        return;
12532                    }
12533
12534                    let mut head = selection.head();
12535                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12536                    if head.column() == display_map.line_len(head.row()) {
12537                        transpose_offset = display_map
12538                            .buffer_snapshot()
12539                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12540                    }
12541
12542                    if transpose_offset == MultiBufferOffset(0) {
12543                        return;
12544                    }
12545
12546                    *head.column_mut() += 1;
12547                    head = display_map.clip_point(head, Bias::Right);
12548                    let goal = SelectionGoal::HorizontalPosition(
12549                        display_map
12550                            .x_for_display_point(head, text_layout_details)
12551                            .into(),
12552                    );
12553                    selection.collapse_to(head, goal);
12554
12555                    let transpose_start = display_map
12556                        .buffer_snapshot()
12557                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12558                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12559                        let transpose_end = display_map
12560                            .buffer_snapshot()
12561                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12562                        if let Some(ch) = display_map
12563                            .buffer_snapshot()
12564                            .chars_at(transpose_start)
12565                            .next()
12566                        {
12567                            edits.push((transpose_start..transpose_offset, String::new()));
12568                            edits.push((transpose_end..transpose_end, ch.to_string()));
12569                        }
12570                    }
12571                });
12572                edits
12573            });
12574            this.buffer
12575                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12576            let selections = this
12577                .selections
12578                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12579            this.change_selections(Default::default(), window, cx, |s| {
12580                s.select(selections);
12581            });
12582        });
12583    }
12584
12585    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12586        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12587        if self.mode.is_single_line() {
12588            cx.propagate();
12589            return;
12590        }
12591
12592        self.rewrap_impl(RewrapOptions::default(), cx)
12593    }
12594
12595    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12596        let buffer = self.buffer.read(cx).snapshot(cx);
12597        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12598
12599        #[derive(Clone, Debug, PartialEq)]
12600        enum CommentFormat {
12601            /// single line comment, with prefix for line
12602            Line(String),
12603            /// single line within a block comment, with prefix for line
12604            BlockLine(String),
12605            /// a single line of a block comment that includes the initial delimiter
12606            BlockCommentWithStart(BlockCommentConfig),
12607            /// a single line of a block comment that includes the ending delimiter
12608            BlockCommentWithEnd(BlockCommentConfig),
12609        }
12610
12611        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12612        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12613            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12614                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12615                .peekable();
12616
12617            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12618                row
12619            } else {
12620                return Vec::new();
12621            };
12622
12623            let language_settings = buffer.language_settings_at(selection.head(), cx);
12624            let language_scope = buffer.language_scope_at(selection.head());
12625
12626            let indent_and_prefix_for_row =
12627                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12628                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12629                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12630                        &language_scope
12631                    {
12632                        let indent_end = Point::new(row, indent.len);
12633                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12634                        let line_text_after_indent = buffer
12635                            .text_for_range(indent_end..line_end)
12636                            .collect::<String>();
12637
12638                        let is_within_comment_override = buffer
12639                            .language_scope_at(indent_end)
12640                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12641                        let comment_delimiters = if is_within_comment_override {
12642                            // we are within a comment syntax node, but we don't
12643                            // yet know what kind of comment: block, doc or line
12644                            match (
12645                                language_scope.documentation_comment(),
12646                                language_scope.block_comment(),
12647                            ) {
12648                                (Some(config), _) | (_, Some(config))
12649                                    if buffer.contains_str_at(indent_end, &config.start) =>
12650                                {
12651                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12652                                }
12653                                (Some(config), _) | (_, Some(config))
12654                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12655                                {
12656                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12657                                }
12658                                (Some(config), _) | (_, Some(config))
12659                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12660                                {
12661                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12662                                }
12663                                (_, _) => language_scope
12664                                    .line_comment_prefixes()
12665                                    .iter()
12666                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12667                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12668                            }
12669                        } else {
12670                            // we not in an overridden comment node, but we may
12671                            // be within a non-overridden line comment node
12672                            language_scope
12673                                .line_comment_prefixes()
12674                                .iter()
12675                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12676                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12677                        };
12678
12679                        let rewrap_prefix = language_scope
12680                            .rewrap_prefixes()
12681                            .iter()
12682                            .find_map(|prefix_regex| {
12683                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12684                                    if mat.start() == 0 {
12685                                        Some(mat.as_str().to_string())
12686                                    } else {
12687                                        None
12688                                    }
12689                                })
12690                            })
12691                            .flatten();
12692                        (comment_delimiters, rewrap_prefix)
12693                    } else {
12694                        (None, None)
12695                    };
12696                    (indent, comment_prefix, rewrap_prefix)
12697                };
12698
12699            let mut ranges = Vec::new();
12700            let from_empty_selection = selection.is_empty();
12701
12702            let mut current_range_start = first_row;
12703            let mut prev_row = first_row;
12704            let (
12705                mut current_range_indent,
12706                mut current_range_comment_delimiters,
12707                mut current_range_rewrap_prefix,
12708            ) = indent_and_prefix_for_row(first_row);
12709
12710            for row in non_blank_rows_iter.skip(1) {
12711                let has_paragraph_break = row > prev_row + 1;
12712
12713                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12714                    indent_and_prefix_for_row(row);
12715
12716                let has_indent_change = row_indent != current_range_indent;
12717                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12718
12719                let has_boundary_change = has_comment_change
12720                    || row_rewrap_prefix.is_some()
12721                    || (has_indent_change && current_range_comment_delimiters.is_some());
12722
12723                if has_paragraph_break || has_boundary_change {
12724                    ranges.push((
12725                        language_settings.clone(),
12726                        Point::new(current_range_start, 0)
12727                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12728                        current_range_indent,
12729                        current_range_comment_delimiters.clone(),
12730                        current_range_rewrap_prefix.clone(),
12731                        from_empty_selection,
12732                    ));
12733                    current_range_start = row;
12734                    current_range_indent = row_indent;
12735                    current_range_comment_delimiters = row_comment_delimiters;
12736                    current_range_rewrap_prefix = row_rewrap_prefix;
12737                }
12738                prev_row = row;
12739            }
12740
12741            ranges.push((
12742                language_settings.clone(),
12743                Point::new(current_range_start, 0)
12744                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12745                current_range_indent,
12746                current_range_comment_delimiters,
12747                current_range_rewrap_prefix,
12748                from_empty_selection,
12749            ));
12750
12751            ranges
12752        });
12753
12754        let mut edits = Vec::new();
12755        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12756
12757        for (
12758            language_settings,
12759            wrap_range,
12760            mut indent_size,
12761            comment_prefix,
12762            rewrap_prefix,
12763            from_empty_selection,
12764        ) in wrap_ranges
12765        {
12766            let mut start_row = wrap_range.start.row;
12767            let mut end_row = wrap_range.end.row;
12768
12769            // Skip selections that overlap with a range that has already been rewrapped.
12770            let selection_range = start_row..end_row;
12771            if rewrapped_row_ranges
12772                .iter()
12773                .any(|range| range.overlaps(&selection_range))
12774            {
12775                continue;
12776            }
12777
12778            let tab_size = language_settings.tab_size;
12779
12780            let (line_prefix, inside_comment) = match &comment_prefix {
12781                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12782                    (Some(prefix.as_str()), true)
12783                }
12784                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12785                    (Some(prefix.as_ref()), true)
12786                }
12787                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12788                    start: _,
12789                    end: _,
12790                    prefix,
12791                    tab_size,
12792                })) => {
12793                    indent_size.len += tab_size;
12794                    (Some(prefix.as_ref()), true)
12795                }
12796                None => (None, false),
12797            };
12798            let indent_prefix = indent_size.chars().collect::<String>();
12799            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12800
12801            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12802                RewrapBehavior::InComments => inside_comment,
12803                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12804                RewrapBehavior::Anywhere => true,
12805            };
12806
12807            let should_rewrap = options.override_language_settings
12808                || allow_rewrap_based_on_language
12809                || self.hard_wrap.is_some();
12810            if !should_rewrap {
12811                continue;
12812            }
12813
12814            if from_empty_selection {
12815                'expand_upwards: while start_row > 0 {
12816                    let prev_row = start_row - 1;
12817                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12818                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12819                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12820                    {
12821                        start_row = prev_row;
12822                    } else {
12823                        break 'expand_upwards;
12824                    }
12825                }
12826
12827                'expand_downwards: while end_row < buffer.max_point().row {
12828                    let next_row = end_row + 1;
12829                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12830                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12831                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12832                    {
12833                        end_row = next_row;
12834                    } else {
12835                        break 'expand_downwards;
12836                    }
12837                }
12838            }
12839
12840            let start = Point::new(start_row, 0);
12841            let start_offset = ToOffset::to_offset(&start, &buffer);
12842            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12843            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12844            let mut first_line_delimiter = None;
12845            let mut last_line_delimiter = None;
12846            let Some(lines_without_prefixes) = selection_text
12847                .lines()
12848                .enumerate()
12849                .map(|(ix, line)| {
12850                    let line_trimmed = line.trim_start();
12851                    if rewrap_prefix.is_some() && ix > 0 {
12852                        Ok(line_trimmed)
12853                    } else if let Some(
12854                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12855                            start,
12856                            prefix,
12857                            end,
12858                            tab_size,
12859                        })
12860                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12861                            start,
12862                            prefix,
12863                            end,
12864                            tab_size,
12865                        }),
12866                    ) = &comment_prefix
12867                    {
12868                        let line_trimmed = line_trimmed
12869                            .strip_prefix(start.as_ref())
12870                            .map(|s| {
12871                                let mut indent_size = indent_size;
12872                                indent_size.len -= tab_size;
12873                                let indent_prefix: String = indent_size.chars().collect();
12874                                first_line_delimiter = Some((indent_prefix, start));
12875                                s.trim_start()
12876                            })
12877                            .unwrap_or(line_trimmed);
12878                        let line_trimmed = line_trimmed
12879                            .strip_suffix(end.as_ref())
12880                            .map(|s| {
12881                                last_line_delimiter = Some(end);
12882                                s.trim_end()
12883                            })
12884                            .unwrap_or(line_trimmed);
12885                        let line_trimmed = line_trimmed
12886                            .strip_prefix(prefix.as_ref())
12887                            .unwrap_or(line_trimmed);
12888                        Ok(line_trimmed)
12889                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12890                        line_trimmed.strip_prefix(prefix).with_context(|| {
12891                            format!("line did not start with prefix {prefix:?}: {line:?}")
12892                        })
12893                    } else {
12894                        line_trimmed
12895                            .strip_prefix(&line_prefix.trim_start())
12896                            .with_context(|| {
12897                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12898                            })
12899                    }
12900                })
12901                .collect::<Result<Vec<_>, _>>()
12902                .log_err()
12903            else {
12904                continue;
12905            };
12906
12907            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12908                buffer
12909                    .language_settings_at(Point::new(start_row, 0), cx)
12910                    .preferred_line_length as usize
12911            });
12912
12913            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12914                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12915            } else {
12916                line_prefix.clone()
12917            };
12918
12919            let wrapped_text = {
12920                let mut wrapped_text = wrap_with_prefix(
12921                    line_prefix,
12922                    subsequent_lines_prefix,
12923                    lines_without_prefixes.join("\n"),
12924                    wrap_column,
12925                    tab_size,
12926                    options.preserve_existing_whitespace,
12927                );
12928
12929                if let Some((indent, delimiter)) = first_line_delimiter {
12930                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12931                }
12932                if let Some(last_line) = last_line_delimiter {
12933                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12934                }
12935
12936                wrapped_text
12937            };
12938
12939            // TODO: should always use char-based diff while still supporting cursor behavior that
12940            // matches vim.
12941            let mut diff_options = DiffOptions::default();
12942            if options.override_language_settings {
12943                diff_options.max_word_diff_len = 0;
12944                diff_options.max_word_diff_line_count = 0;
12945            } else {
12946                diff_options.max_word_diff_len = usize::MAX;
12947                diff_options.max_word_diff_line_count = usize::MAX;
12948            }
12949
12950            for (old_range, new_text) in
12951                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12952            {
12953                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12954                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12955                edits.push((edit_start..edit_end, new_text));
12956            }
12957
12958            rewrapped_row_ranges.push(start_row..=end_row);
12959        }
12960
12961        self.buffer
12962            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12963    }
12964
12965    pub fn cut_common(
12966        &mut self,
12967        cut_no_selection_line: bool,
12968        window: &mut Window,
12969        cx: &mut Context<Self>,
12970    ) -> ClipboardItem {
12971        let mut text = String::new();
12972        let buffer = self.buffer.read(cx).snapshot(cx);
12973        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12974        let mut clipboard_selections = Vec::with_capacity(selections.len());
12975        {
12976            let max_point = buffer.max_point();
12977            let mut is_first = true;
12978            let mut prev_selection_was_entire_line = false;
12979            for selection in &mut selections {
12980                let is_entire_line =
12981                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12982                if is_entire_line {
12983                    selection.start = Point::new(selection.start.row, 0);
12984                    if !selection.is_empty() && selection.end.column == 0 {
12985                        selection.end = cmp::min(max_point, selection.end);
12986                    } else {
12987                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12988                    }
12989                    selection.goal = SelectionGoal::None;
12990                }
12991                if is_first {
12992                    is_first = false;
12993                } else if !prev_selection_was_entire_line {
12994                    text += "\n";
12995                }
12996                prev_selection_was_entire_line = is_entire_line;
12997                let mut len = 0;
12998                for chunk in buffer.text_for_range(selection.start..selection.end) {
12999                    text.push_str(chunk);
13000                    len += chunk.len();
13001                }
13002
13003                clipboard_selections.push(ClipboardSelection::for_buffer(
13004                    len,
13005                    is_entire_line,
13006                    selection.range(),
13007                    &buffer,
13008                    self.project.as_ref(),
13009                    cx,
13010                ));
13011            }
13012        }
13013
13014        self.transact(window, cx, |this, window, cx| {
13015            this.change_selections(Default::default(), window, cx, |s| {
13016                s.select(selections);
13017            });
13018            this.insert("", window, cx);
13019        });
13020        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13021    }
13022
13023    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13024        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13025        let item = self.cut_common(true, window, cx);
13026        cx.write_to_clipboard(item);
13027    }
13028
13029    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13030        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13031        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13032            s.move_with(|snapshot, sel| {
13033                if sel.is_empty() {
13034                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13035                }
13036                if sel.is_empty() {
13037                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13038                }
13039            });
13040        });
13041        let item = self.cut_common(false, window, cx);
13042        cx.set_global(KillRing(item))
13043    }
13044
13045    pub fn kill_ring_yank(
13046        &mut self,
13047        _: &KillRingYank,
13048        window: &mut Window,
13049        cx: &mut Context<Self>,
13050    ) {
13051        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13052        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13053            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13054                (kill_ring.text().to_string(), kill_ring.metadata_json())
13055            } else {
13056                return;
13057            }
13058        } else {
13059            return;
13060        };
13061        self.do_paste(&text, metadata, false, window, cx);
13062    }
13063
13064    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13065        self.do_copy(true, cx);
13066    }
13067
13068    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13069        self.do_copy(false, cx);
13070    }
13071
13072    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13073        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13074        let buffer = self.buffer.read(cx).read(cx);
13075        let mut text = String::new();
13076
13077        let mut clipboard_selections = Vec::with_capacity(selections.len());
13078        {
13079            let max_point = buffer.max_point();
13080            let mut is_first = true;
13081            let mut prev_selection_was_entire_line = false;
13082            for selection in &selections {
13083                let mut start = selection.start;
13084                let mut end = selection.end;
13085                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13086                let mut add_trailing_newline = false;
13087                if is_entire_line {
13088                    start = Point::new(start.row, 0);
13089                    let next_line_start = Point::new(end.row + 1, 0);
13090                    if next_line_start <= max_point {
13091                        end = next_line_start;
13092                    } else {
13093                        // We're on the last line without a trailing newline.
13094                        // Copy to the end of the line and add a newline afterwards.
13095                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13096                        add_trailing_newline = true;
13097                    }
13098                }
13099
13100                let mut trimmed_selections = Vec::new();
13101                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13102                    let row = MultiBufferRow(start.row);
13103                    let first_indent = buffer.indent_size_for_line(row);
13104                    if first_indent.len == 0 || start.column > first_indent.len {
13105                        trimmed_selections.push(start..end);
13106                    } else {
13107                        trimmed_selections.push(
13108                            Point::new(row.0, first_indent.len)
13109                                ..Point::new(row.0, buffer.line_len(row)),
13110                        );
13111                        for row in start.row + 1..=end.row {
13112                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13113                            if row == end.row {
13114                                line_len = end.column;
13115                            }
13116                            if line_len == 0 {
13117                                trimmed_selections
13118                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13119                                continue;
13120                            }
13121                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13122                            if row_indent_size.len >= first_indent.len {
13123                                trimmed_selections.push(
13124                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13125                                );
13126                            } else {
13127                                trimmed_selections.clear();
13128                                trimmed_selections.push(start..end);
13129                                break;
13130                            }
13131                        }
13132                    }
13133                } else {
13134                    trimmed_selections.push(start..end);
13135                }
13136
13137                for trimmed_range in trimmed_selections {
13138                    if is_first {
13139                        is_first = false;
13140                    } else if !prev_selection_was_entire_line {
13141                        text += "\n";
13142                    }
13143                    prev_selection_was_entire_line = is_entire_line;
13144                    let mut len = 0;
13145                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13146                        text.push_str(chunk);
13147                        len += chunk.len();
13148                    }
13149                    if add_trailing_newline {
13150                        text.push('\n');
13151                        len += 1;
13152                    }
13153                    clipboard_selections.push(ClipboardSelection::for_buffer(
13154                        len,
13155                        is_entire_line,
13156                        trimmed_range,
13157                        &buffer,
13158                        self.project.as_ref(),
13159                        cx,
13160                    ));
13161                }
13162            }
13163        }
13164
13165        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13166            text,
13167            clipboard_selections,
13168        ));
13169    }
13170
13171    pub fn do_paste(
13172        &mut self,
13173        text: &String,
13174        clipboard_selections: Option<Vec<ClipboardSelection>>,
13175        handle_entire_lines: bool,
13176        window: &mut Window,
13177        cx: &mut Context<Self>,
13178    ) {
13179        if self.read_only(cx) {
13180            return;
13181        }
13182
13183        let clipboard_text = Cow::Borrowed(text.as_str());
13184
13185        self.transact(window, cx, |this, window, cx| {
13186            let had_active_edit_prediction = this.has_active_edit_prediction();
13187            let display_map = this.display_snapshot(cx);
13188            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13189            let cursor_offset = this
13190                .selections
13191                .last::<MultiBufferOffset>(&display_map)
13192                .head();
13193
13194            if let Some(mut clipboard_selections) = clipboard_selections {
13195                let all_selections_were_entire_line =
13196                    clipboard_selections.iter().all(|s| s.is_entire_line);
13197                let first_selection_indent_column =
13198                    clipboard_selections.first().map(|s| s.first_line_indent);
13199                if clipboard_selections.len() != old_selections.len() {
13200                    clipboard_selections.drain(..);
13201                }
13202                let mut auto_indent_on_paste = true;
13203
13204                this.buffer.update(cx, |buffer, cx| {
13205                    let snapshot = buffer.read(cx);
13206                    auto_indent_on_paste = snapshot
13207                        .language_settings_at(cursor_offset, cx)
13208                        .auto_indent_on_paste;
13209
13210                    let mut start_offset = 0;
13211                    let mut edits = Vec::new();
13212                    let mut original_indent_columns = Vec::new();
13213                    for (ix, selection) in old_selections.iter().enumerate() {
13214                        let to_insert;
13215                        let entire_line;
13216                        let original_indent_column;
13217                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13218                            let end_offset = start_offset + clipboard_selection.len;
13219                            to_insert = &clipboard_text[start_offset..end_offset];
13220                            entire_line = clipboard_selection.is_entire_line;
13221                            start_offset = if entire_line {
13222                                end_offset
13223                            } else {
13224                                end_offset + 1
13225                            };
13226                            original_indent_column = Some(clipboard_selection.first_line_indent);
13227                        } else {
13228                            to_insert = &*clipboard_text;
13229                            entire_line = all_selections_were_entire_line;
13230                            original_indent_column = first_selection_indent_column
13231                        }
13232
13233                        let (range, to_insert) =
13234                            if selection.is_empty() && handle_entire_lines && entire_line {
13235                                // If the corresponding selection was empty when this slice of the
13236                                // clipboard text was written, then the entire line containing the
13237                                // selection was copied. If this selection is also currently empty,
13238                                // then paste the line before the current line of the buffer.
13239                                let column = selection.start.to_point(&snapshot).column as usize;
13240                                let line_start = selection.start - column;
13241                                (line_start..line_start, Cow::Borrowed(to_insert))
13242                            } else {
13243                                let language = snapshot.language_at(selection.head());
13244                                let range = selection.range();
13245                                if let Some(language) = language
13246                                    && language.name() == "Markdown".into()
13247                                {
13248                                    edit_for_markdown_paste(
13249                                        &snapshot,
13250                                        range,
13251                                        to_insert,
13252                                        url::Url::parse(to_insert).ok(),
13253                                    )
13254                                } else {
13255                                    (range, Cow::Borrowed(to_insert))
13256                                }
13257                            };
13258
13259                        edits.push((range, to_insert));
13260                        original_indent_columns.push(original_indent_column);
13261                    }
13262                    drop(snapshot);
13263
13264                    buffer.edit(
13265                        edits,
13266                        if auto_indent_on_paste {
13267                            Some(AutoindentMode::Block {
13268                                original_indent_columns,
13269                            })
13270                        } else {
13271                            None
13272                        },
13273                        cx,
13274                    );
13275                });
13276
13277                let selections = this
13278                    .selections
13279                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13280                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13281            } else {
13282                let url = url::Url::parse(&clipboard_text).ok();
13283
13284                let auto_indent_mode = if !clipboard_text.is_empty() {
13285                    Some(AutoindentMode::Block {
13286                        original_indent_columns: Vec::new(),
13287                    })
13288                } else {
13289                    None
13290                };
13291
13292                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13293                    let snapshot = buffer.snapshot(cx);
13294
13295                    let anchors = old_selections
13296                        .iter()
13297                        .map(|s| {
13298                            let anchor = snapshot.anchor_after(s.head());
13299                            s.map(|_| anchor)
13300                        })
13301                        .collect::<Vec<_>>();
13302
13303                    let mut edits = Vec::new();
13304
13305                    for selection in old_selections.iter() {
13306                        let language = snapshot.language_at(selection.head());
13307                        let range = selection.range();
13308
13309                        let (edit_range, edit_text) = if let Some(language) = language
13310                            && language.name() == "Markdown".into()
13311                        {
13312                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13313                        } else {
13314                            (range, clipboard_text.clone())
13315                        };
13316
13317                        edits.push((edit_range, edit_text));
13318                    }
13319
13320                    drop(snapshot);
13321                    buffer.edit(edits, auto_indent_mode, cx);
13322
13323                    anchors
13324                });
13325
13326                this.change_selections(Default::default(), window, cx, |s| {
13327                    s.select_anchors(selection_anchors);
13328                });
13329            }
13330
13331            //   🤔                 |    ..     | show_in_menu |
13332            // | ..                  |   true        true
13333            // | had_edit_prediction |   false       true
13334
13335            let trigger_in_words =
13336                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13337
13338            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13339        });
13340    }
13341
13342    pub fn diff_clipboard_with_selection(
13343        &mut self,
13344        _: &DiffClipboardWithSelection,
13345        window: &mut Window,
13346        cx: &mut Context<Self>,
13347    ) {
13348        let selections = self
13349            .selections
13350            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13351
13352        if selections.is_empty() {
13353            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13354            return;
13355        };
13356
13357        let clipboard_text = match cx.read_from_clipboard() {
13358            Some(item) => match item.entries().first() {
13359                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13360                _ => None,
13361            },
13362            None => None,
13363        };
13364
13365        let Some(clipboard_text) = clipboard_text else {
13366            log::warn!("Clipboard doesn't contain text.");
13367            return;
13368        };
13369
13370        window.dispatch_action(
13371            Box::new(DiffClipboardWithSelectionData {
13372                clipboard_text,
13373                editor: cx.entity(),
13374            }),
13375            cx,
13376        );
13377    }
13378
13379    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13380        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13381        if let Some(item) = cx.read_from_clipboard() {
13382            let entries = item.entries();
13383
13384            match entries.first() {
13385                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13386                // of all the pasted entries.
13387                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13388                    .do_paste(
13389                        clipboard_string.text(),
13390                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13391                        true,
13392                        window,
13393                        cx,
13394                    ),
13395                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13396            }
13397        }
13398    }
13399
13400    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13401        if self.read_only(cx) {
13402            return;
13403        }
13404
13405        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13406
13407        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13408            if let Some((selections, _)) =
13409                self.selection_history.transaction(transaction_id).cloned()
13410            {
13411                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13412                    s.select_anchors(selections.to_vec());
13413                });
13414            } else {
13415                log::error!(
13416                    "No entry in selection_history found for undo. \
13417                     This may correspond to a bug where undo does not update the selection. \
13418                     If this is occurring, please add details to \
13419                     https://github.com/zed-industries/zed/issues/22692"
13420                );
13421            }
13422            self.request_autoscroll(Autoscroll::fit(), cx);
13423            self.unmark_text(window, cx);
13424            self.refresh_edit_prediction(true, false, window, cx);
13425            cx.emit(EditorEvent::Edited { transaction_id });
13426            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13427        }
13428    }
13429
13430    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13431        if self.read_only(cx) {
13432            return;
13433        }
13434
13435        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13436
13437        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13438            if let Some((_, Some(selections))) =
13439                self.selection_history.transaction(transaction_id).cloned()
13440            {
13441                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13442                    s.select_anchors(selections.to_vec());
13443                });
13444            } else {
13445                log::error!(
13446                    "No entry in selection_history found for redo. \
13447                     This may correspond to a bug where undo does not update the selection. \
13448                     If this is occurring, please add details to \
13449                     https://github.com/zed-industries/zed/issues/22692"
13450                );
13451            }
13452            self.request_autoscroll(Autoscroll::fit(), cx);
13453            self.unmark_text(window, cx);
13454            self.refresh_edit_prediction(true, false, window, cx);
13455            cx.emit(EditorEvent::Edited { transaction_id });
13456        }
13457    }
13458
13459    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13460        self.buffer
13461            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13462    }
13463
13464    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13465        self.buffer
13466            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13467    }
13468
13469    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13470        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13471        self.change_selections(Default::default(), window, cx, |s| {
13472            s.move_with(|map, selection| {
13473                let cursor = if selection.is_empty() {
13474                    movement::left(map, selection.start)
13475                } else {
13476                    selection.start
13477                };
13478                selection.collapse_to(cursor, SelectionGoal::None);
13479            });
13480        })
13481    }
13482
13483    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13484        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13485        self.change_selections(Default::default(), window, cx, |s| {
13486            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13487        })
13488    }
13489
13490    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13491        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13492        self.change_selections(Default::default(), window, cx, |s| {
13493            s.move_with(|map, selection| {
13494                let cursor = if selection.is_empty() {
13495                    movement::right(map, selection.end)
13496                } else {
13497                    selection.end
13498                };
13499                selection.collapse_to(cursor, SelectionGoal::None)
13500            });
13501        })
13502    }
13503
13504    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13505        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13506        self.change_selections(Default::default(), window, cx, |s| {
13507            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13508        });
13509    }
13510
13511    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13512        if self.take_rename(true, window, cx).is_some() {
13513            return;
13514        }
13515
13516        if self.mode.is_single_line() {
13517            cx.propagate();
13518            return;
13519        }
13520
13521        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13522
13523        let text_layout_details = &self.text_layout_details(window);
13524        let selection_count = self.selections.count();
13525        let first_selection = self.selections.first_anchor();
13526
13527        self.change_selections(Default::default(), window, cx, |s| {
13528            s.move_with(|map, selection| {
13529                if !selection.is_empty() {
13530                    selection.goal = SelectionGoal::None;
13531                }
13532                let (cursor, goal) = movement::up(
13533                    map,
13534                    selection.start,
13535                    selection.goal,
13536                    false,
13537                    text_layout_details,
13538                );
13539                selection.collapse_to(cursor, goal);
13540            });
13541        });
13542
13543        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13544        {
13545            cx.propagate();
13546        }
13547    }
13548
13549    pub fn move_up_by_lines(
13550        &mut self,
13551        action: &MoveUpByLines,
13552        window: &mut Window,
13553        cx: &mut Context<Self>,
13554    ) {
13555        if self.take_rename(true, window, cx).is_some() {
13556            return;
13557        }
13558
13559        if self.mode.is_single_line() {
13560            cx.propagate();
13561            return;
13562        }
13563
13564        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13565
13566        let text_layout_details = &self.text_layout_details(window);
13567
13568        self.change_selections(Default::default(), window, cx, |s| {
13569            s.move_with(|map, selection| {
13570                if !selection.is_empty() {
13571                    selection.goal = SelectionGoal::None;
13572                }
13573                let (cursor, goal) = movement::up_by_rows(
13574                    map,
13575                    selection.start,
13576                    action.lines,
13577                    selection.goal,
13578                    false,
13579                    text_layout_details,
13580                );
13581                selection.collapse_to(cursor, goal);
13582            });
13583        })
13584    }
13585
13586    pub fn move_down_by_lines(
13587        &mut self,
13588        action: &MoveDownByLines,
13589        window: &mut Window,
13590        cx: &mut Context<Self>,
13591    ) {
13592        if self.take_rename(true, window, cx).is_some() {
13593            return;
13594        }
13595
13596        if self.mode.is_single_line() {
13597            cx.propagate();
13598            return;
13599        }
13600
13601        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13602
13603        let text_layout_details = &self.text_layout_details(window);
13604
13605        self.change_selections(Default::default(), window, cx, |s| {
13606            s.move_with(|map, selection| {
13607                if !selection.is_empty() {
13608                    selection.goal = SelectionGoal::None;
13609                }
13610                let (cursor, goal) = movement::down_by_rows(
13611                    map,
13612                    selection.start,
13613                    action.lines,
13614                    selection.goal,
13615                    false,
13616                    text_layout_details,
13617                );
13618                selection.collapse_to(cursor, goal);
13619            });
13620        })
13621    }
13622
13623    pub fn select_down_by_lines(
13624        &mut self,
13625        action: &SelectDownByLines,
13626        window: &mut Window,
13627        cx: &mut Context<Self>,
13628    ) {
13629        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13630        let text_layout_details = &self.text_layout_details(window);
13631        self.change_selections(Default::default(), window, cx, |s| {
13632            s.move_heads_with(|map, head, goal| {
13633                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13634            })
13635        })
13636    }
13637
13638    pub fn select_up_by_lines(
13639        &mut self,
13640        action: &SelectUpByLines,
13641        window: &mut Window,
13642        cx: &mut Context<Self>,
13643    ) {
13644        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13645        let text_layout_details = &self.text_layout_details(window);
13646        self.change_selections(Default::default(), window, cx, |s| {
13647            s.move_heads_with(|map, head, goal| {
13648                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13649            })
13650        })
13651    }
13652
13653    pub fn select_page_up(
13654        &mut self,
13655        _: &SelectPageUp,
13656        window: &mut Window,
13657        cx: &mut Context<Self>,
13658    ) {
13659        let Some(row_count) = self.visible_row_count() else {
13660            return;
13661        };
13662
13663        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13664
13665        let text_layout_details = &self.text_layout_details(window);
13666
13667        self.change_selections(Default::default(), window, cx, |s| {
13668            s.move_heads_with(|map, head, goal| {
13669                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13670            })
13671        })
13672    }
13673
13674    pub fn move_page_up(
13675        &mut self,
13676        action: &MovePageUp,
13677        window: &mut Window,
13678        cx: &mut Context<Self>,
13679    ) {
13680        if self.take_rename(true, window, cx).is_some() {
13681            return;
13682        }
13683
13684        if self
13685            .context_menu
13686            .borrow_mut()
13687            .as_mut()
13688            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13689            .unwrap_or(false)
13690        {
13691            return;
13692        }
13693
13694        if matches!(self.mode, EditorMode::SingleLine) {
13695            cx.propagate();
13696            return;
13697        }
13698
13699        let Some(row_count) = self.visible_row_count() else {
13700            return;
13701        };
13702
13703        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13704
13705        let effects = if action.center_cursor {
13706            SelectionEffects::scroll(Autoscroll::center())
13707        } else {
13708            SelectionEffects::default()
13709        };
13710
13711        let text_layout_details = &self.text_layout_details(window);
13712
13713        self.change_selections(effects, window, cx, |s| {
13714            s.move_with(|map, selection| {
13715                if !selection.is_empty() {
13716                    selection.goal = SelectionGoal::None;
13717                }
13718                let (cursor, goal) = movement::up_by_rows(
13719                    map,
13720                    selection.end,
13721                    row_count,
13722                    selection.goal,
13723                    false,
13724                    text_layout_details,
13725                );
13726                selection.collapse_to(cursor, goal);
13727            });
13728        });
13729    }
13730
13731    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13732        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13733        let text_layout_details = &self.text_layout_details(window);
13734        self.change_selections(Default::default(), window, cx, |s| {
13735            s.move_heads_with(|map, head, goal| {
13736                movement::up(map, head, goal, false, text_layout_details)
13737            })
13738        })
13739    }
13740
13741    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13742        self.take_rename(true, window, cx);
13743
13744        if self.mode.is_single_line() {
13745            cx.propagate();
13746            return;
13747        }
13748
13749        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13750
13751        let text_layout_details = &self.text_layout_details(window);
13752        let selection_count = self.selections.count();
13753        let first_selection = self.selections.first_anchor();
13754
13755        self.change_selections(Default::default(), window, cx, |s| {
13756            s.move_with(|map, selection| {
13757                if !selection.is_empty() {
13758                    selection.goal = SelectionGoal::None;
13759                }
13760                let (cursor, goal) = movement::down(
13761                    map,
13762                    selection.end,
13763                    selection.goal,
13764                    false,
13765                    text_layout_details,
13766                );
13767                selection.collapse_to(cursor, goal);
13768            });
13769        });
13770
13771        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13772        {
13773            cx.propagate();
13774        }
13775    }
13776
13777    pub fn select_page_down(
13778        &mut self,
13779        _: &SelectPageDown,
13780        window: &mut Window,
13781        cx: &mut Context<Self>,
13782    ) {
13783        let Some(row_count) = self.visible_row_count() else {
13784            return;
13785        };
13786
13787        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13788
13789        let text_layout_details = &self.text_layout_details(window);
13790
13791        self.change_selections(Default::default(), window, cx, |s| {
13792            s.move_heads_with(|map, head, goal| {
13793                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13794            })
13795        })
13796    }
13797
13798    pub fn move_page_down(
13799        &mut self,
13800        action: &MovePageDown,
13801        window: &mut Window,
13802        cx: &mut Context<Self>,
13803    ) {
13804        if self.take_rename(true, window, cx).is_some() {
13805            return;
13806        }
13807
13808        if self
13809            .context_menu
13810            .borrow_mut()
13811            .as_mut()
13812            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13813            .unwrap_or(false)
13814        {
13815            return;
13816        }
13817
13818        if matches!(self.mode, EditorMode::SingleLine) {
13819            cx.propagate();
13820            return;
13821        }
13822
13823        let Some(row_count) = self.visible_row_count() else {
13824            return;
13825        };
13826
13827        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13828
13829        let effects = if action.center_cursor {
13830            SelectionEffects::scroll(Autoscroll::center())
13831        } else {
13832            SelectionEffects::default()
13833        };
13834
13835        let text_layout_details = &self.text_layout_details(window);
13836        self.change_selections(effects, window, cx, |s| {
13837            s.move_with(|map, selection| {
13838                if !selection.is_empty() {
13839                    selection.goal = SelectionGoal::None;
13840                }
13841                let (cursor, goal) = movement::down_by_rows(
13842                    map,
13843                    selection.end,
13844                    row_count,
13845                    selection.goal,
13846                    false,
13847                    text_layout_details,
13848                );
13849                selection.collapse_to(cursor, goal);
13850            });
13851        });
13852    }
13853
13854    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13855        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13856        let text_layout_details = &self.text_layout_details(window);
13857        self.change_selections(Default::default(), window, cx, |s| {
13858            s.move_heads_with(|map, head, goal| {
13859                movement::down(map, head, goal, false, text_layout_details)
13860            })
13861        });
13862    }
13863
13864    pub fn context_menu_first(
13865        &mut self,
13866        _: &ContextMenuFirst,
13867        window: &mut Window,
13868        cx: &mut Context<Self>,
13869    ) {
13870        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13871            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13872        }
13873    }
13874
13875    pub fn context_menu_prev(
13876        &mut self,
13877        _: &ContextMenuPrevious,
13878        window: &mut Window,
13879        cx: &mut Context<Self>,
13880    ) {
13881        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13882            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13883        }
13884    }
13885
13886    pub fn context_menu_next(
13887        &mut self,
13888        _: &ContextMenuNext,
13889        window: &mut Window,
13890        cx: &mut Context<Self>,
13891    ) {
13892        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13893            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13894        }
13895    }
13896
13897    pub fn context_menu_last(
13898        &mut self,
13899        _: &ContextMenuLast,
13900        window: &mut Window,
13901        cx: &mut Context<Self>,
13902    ) {
13903        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13904            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13905        }
13906    }
13907
13908    pub fn signature_help_prev(
13909        &mut self,
13910        _: &SignatureHelpPrevious,
13911        _: &mut Window,
13912        cx: &mut Context<Self>,
13913    ) {
13914        if let Some(popover) = self.signature_help_state.popover_mut() {
13915            if popover.current_signature == 0 {
13916                popover.current_signature = popover.signatures.len() - 1;
13917            } else {
13918                popover.current_signature -= 1;
13919            }
13920            cx.notify();
13921        }
13922    }
13923
13924    pub fn signature_help_next(
13925        &mut self,
13926        _: &SignatureHelpNext,
13927        _: &mut Window,
13928        cx: &mut Context<Self>,
13929    ) {
13930        if let Some(popover) = self.signature_help_state.popover_mut() {
13931            if popover.current_signature + 1 == popover.signatures.len() {
13932                popover.current_signature = 0;
13933            } else {
13934                popover.current_signature += 1;
13935            }
13936            cx.notify();
13937        }
13938    }
13939
13940    pub fn move_to_previous_word_start(
13941        &mut self,
13942        _: &MoveToPreviousWordStart,
13943        window: &mut Window,
13944        cx: &mut Context<Self>,
13945    ) {
13946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13947        self.change_selections(Default::default(), window, cx, |s| {
13948            s.move_cursors_with(|map, head, _| {
13949                (
13950                    movement::previous_word_start(map, head),
13951                    SelectionGoal::None,
13952                )
13953            });
13954        })
13955    }
13956
13957    pub fn move_to_previous_subword_start(
13958        &mut self,
13959        _: &MoveToPreviousSubwordStart,
13960        window: &mut Window,
13961        cx: &mut Context<Self>,
13962    ) {
13963        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13964        self.change_selections(Default::default(), window, cx, |s| {
13965            s.move_cursors_with(|map, head, _| {
13966                (
13967                    movement::previous_subword_start(map, head),
13968                    SelectionGoal::None,
13969                )
13970            });
13971        })
13972    }
13973
13974    pub fn select_to_previous_word_start(
13975        &mut self,
13976        _: &SelectToPreviousWordStart,
13977        window: &mut Window,
13978        cx: &mut Context<Self>,
13979    ) {
13980        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13981        self.change_selections(Default::default(), window, cx, |s| {
13982            s.move_heads_with(|map, head, _| {
13983                (
13984                    movement::previous_word_start(map, head),
13985                    SelectionGoal::None,
13986                )
13987            });
13988        })
13989    }
13990
13991    pub fn select_to_previous_subword_start(
13992        &mut self,
13993        _: &SelectToPreviousSubwordStart,
13994        window: &mut Window,
13995        cx: &mut Context<Self>,
13996    ) {
13997        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13998        self.change_selections(Default::default(), window, cx, |s| {
13999            s.move_heads_with(|map, head, _| {
14000                (
14001                    movement::previous_subword_start(map, head),
14002                    SelectionGoal::None,
14003                )
14004            });
14005        })
14006    }
14007
14008    pub fn delete_to_previous_word_start(
14009        &mut self,
14010        action: &DeleteToPreviousWordStart,
14011        window: &mut Window,
14012        cx: &mut Context<Self>,
14013    ) {
14014        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14015        self.transact(window, cx, |this, window, cx| {
14016            this.select_autoclose_pair(window, cx);
14017            this.change_selections(Default::default(), window, cx, |s| {
14018                s.move_with(|map, selection| {
14019                    if selection.is_empty() {
14020                        let mut cursor = if action.ignore_newlines {
14021                            movement::previous_word_start(map, selection.head())
14022                        } else {
14023                            movement::previous_word_start_or_newline(map, selection.head())
14024                        };
14025                        cursor = movement::adjust_greedy_deletion(
14026                            map,
14027                            selection.head(),
14028                            cursor,
14029                            action.ignore_brackets,
14030                        );
14031                        selection.set_head(cursor, SelectionGoal::None);
14032                    }
14033                });
14034            });
14035            this.insert("", window, cx);
14036        });
14037    }
14038
14039    pub fn delete_to_previous_subword_start(
14040        &mut self,
14041        _: &DeleteToPreviousSubwordStart,
14042        window: &mut Window,
14043        cx: &mut Context<Self>,
14044    ) {
14045        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14046        self.transact(window, cx, |this, window, cx| {
14047            this.select_autoclose_pair(window, cx);
14048            this.change_selections(Default::default(), window, cx, |s| {
14049                s.move_with(|map, selection| {
14050                    if selection.is_empty() {
14051                        let mut cursor = movement::previous_subword_start(map, selection.head());
14052                        cursor =
14053                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14054                        selection.set_head(cursor, SelectionGoal::None);
14055                    }
14056                });
14057            });
14058            this.insert("", window, cx);
14059        });
14060    }
14061
14062    pub fn move_to_next_word_end(
14063        &mut self,
14064        _: &MoveToNextWordEnd,
14065        window: &mut Window,
14066        cx: &mut Context<Self>,
14067    ) {
14068        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14069        self.change_selections(Default::default(), window, cx, |s| {
14070            s.move_cursors_with(|map, head, _| {
14071                (movement::next_word_end(map, head), SelectionGoal::None)
14072            });
14073        })
14074    }
14075
14076    pub fn move_to_next_subword_end(
14077        &mut self,
14078        _: &MoveToNextSubwordEnd,
14079        window: &mut Window,
14080        cx: &mut Context<Self>,
14081    ) {
14082        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14083        self.change_selections(Default::default(), window, cx, |s| {
14084            s.move_cursors_with(|map, head, _| {
14085                (movement::next_subword_end(map, head), SelectionGoal::None)
14086            });
14087        })
14088    }
14089
14090    pub fn select_to_next_word_end(
14091        &mut self,
14092        _: &SelectToNextWordEnd,
14093        window: &mut Window,
14094        cx: &mut Context<Self>,
14095    ) {
14096        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14097        self.change_selections(Default::default(), window, cx, |s| {
14098            s.move_heads_with(|map, head, _| {
14099                (movement::next_word_end(map, head), SelectionGoal::None)
14100            });
14101        })
14102    }
14103
14104    pub fn select_to_next_subword_end(
14105        &mut self,
14106        _: &SelectToNextSubwordEnd,
14107        window: &mut Window,
14108        cx: &mut Context<Self>,
14109    ) {
14110        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14111        self.change_selections(Default::default(), window, cx, |s| {
14112            s.move_heads_with(|map, head, _| {
14113                (movement::next_subword_end(map, head), SelectionGoal::None)
14114            });
14115        })
14116    }
14117
14118    pub fn delete_to_next_word_end(
14119        &mut self,
14120        action: &DeleteToNextWordEnd,
14121        window: &mut Window,
14122        cx: &mut Context<Self>,
14123    ) {
14124        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14125        self.transact(window, cx, |this, window, cx| {
14126            this.change_selections(Default::default(), window, cx, |s| {
14127                s.move_with(|map, selection| {
14128                    if selection.is_empty() {
14129                        let mut cursor = if action.ignore_newlines {
14130                            movement::next_word_end(map, selection.head())
14131                        } else {
14132                            movement::next_word_end_or_newline(map, selection.head())
14133                        };
14134                        cursor = movement::adjust_greedy_deletion(
14135                            map,
14136                            selection.head(),
14137                            cursor,
14138                            action.ignore_brackets,
14139                        );
14140                        selection.set_head(cursor, SelectionGoal::None);
14141                    }
14142                });
14143            });
14144            this.insert("", window, cx);
14145        });
14146    }
14147
14148    pub fn delete_to_next_subword_end(
14149        &mut self,
14150        _: &DeleteToNextSubwordEnd,
14151        window: &mut Window,
14152        cx: &mut Context<Self>,
14153    ) {
14154        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14155        self.transact(window, cx, |this, window, cx| {
14156            this.change_selections(Default::default(), window, cx, |s| {
14157                s.move_with(|map, selection| {
14158                    if selection.is_empty() {
14159                        let mut cursor = movement::next_subword_end(map, selection.head());
14160                        cursor =
14161                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14162                        selection.set_head(cursor, SelectionGoal::None);
14163                    }
14164                });
14165            });
14166            this.insert("", window, cx);
14167        });
14168    }
14169
14170    pub fn move_to_beginning_of_line(
14171        &mut self,
14172        action: &MoveToBeginningOfLine,
14173        window: &mut Window,
14174        cx: &mut Context<Self>,
14175    ) {
14176        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14177        self.change_selections(Default::default(), window, cx, |s| {
14178            s.move_cursors_with(|map, head, _| {
14179                (
14180                    movement::indented_line_beginning(
14181                        map,
14182                        head,
14183                        action.stop_at_soft_wraps,
14184                        action.stop_at_indent,
14185                    ),
14186                    SelectionGoal::None,
14187                )
14188            });
14189        })
14190    }
14191
14192    pub fn select_to_beginning_of_line(
14193        &mut self,
14194        action: &SelectToBeginningOfLine,
14195        window: &mut Window,
14196        cx: &mut Context<Self>,
14197    ) {
14198        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14199        self.change_selections(Default::default(), window, cx, |s| {
14200            s.move_heads_with(|map, head, _| {
14201                (
14202                    movement::indented_line_beginning(
14203                        map,
14204                        head,
14205                        action.stop_at_soft_wraps,
14206                        action.stop_at_indent,
14207                    ),
14208                    SelectionGoal::None,
14209                )
14210            });
14211        });
14212    }
14213
14214    pub fn delete_to_beginning_of_line(
14215        &mut self,
14216        action: &DeleteToBeginningOfLine,
14217        window: &mut Window,
14218        cx: &mut Context<Self>,
14219    ) {
14220        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14221        self.transact(window, cx, |this, window, cx| {
14222            this.change_selections(Default::default(), window, cx, |s| {
14223                s.move_with(|_, selection| {
14224                    selection.reversed = true;
14225                });
14226            });
14227
14228            this.select_to_beginning_of_line(
14229                &SelectToBeginningOfLine {
14230                    stop_at_soft_wraps: false,
14231                    stop_at_indent: action.stop_at_indent,
14232                },
14233                window,
14234                cx,
14235            );
14236            this.backspace(&Backspace, window, cx);
14237        });
14238    }
14239
14240    pub fn move_to_end_of_line(
14241        &mut self,
14242        action: &MoveToEndOfLine,
14243        window: &mut Window,
14244        cx: &mut Context<Self>,
14245    ) {
14246        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14247        self.change_selections(Default::default(), window, cx, |s| {
14248            s.move_cursors_with(|map, head, _| {
14249                (
14250                    movement::line_end(map, head, action.stop_at_soft_wraps),
14251                    SelectionGoal::None,
14252                )
14253            });
14254        })
14255    }
14256
14257    pub fn select_to_end_of_line(
14258        &mut self,
14259        action: &SelectToEndOfLine,
14260        window: &mut Window,
14261        cx: &mut Context<Self>,
14262    ) {
14263        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14264        self.change_selections(Default::default(), window, cx, |s| {
14265            s.move_heads_with(|map, head, _| {
14266                (
14267                    movement::line_end(map, head, action.stop_at_soft_wraps),
14268                    SelectionGoal::None,
14269                )
14270            });
14271        })
14272    }
14273
14274    pub fn delete_to_end_of_line(
14275        &mut self,
14276        _: &DeleteToEndOfLine,
14277        window: &mut Window,
14278        cx: &mut Context<Self>,
14279    ) {
14280        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14281        self.transact(window, cx, |this, window, cx| {
14282            this.select_to_end_of_line(
14283                &SelectToEndOfLine {
14284                    stop_at_soft_wraps: false,
14285                },
14286                window,
14287                cx,
14288            );
14289            this.delete(&Delete, window, cx);
14290        });
14291    }
14292
14293    pub fn cut_to_end_of_line(
14294        &mut self,
14295        action: &CutToEndOfLine,
14296        window: &mut Window,
14297        cx: &mut Context<Self>,
14298    ) {
14299        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14300        self.transact(window, cx, |this, window, cx| {
14301            this.select_to_end_of_line(
14302                &SelectToEndOfLine {
14303                    stop_at_soft_wraps: false,
14304                },
14305                window,
14306                cx,
14307            );
14308            if !action.stop_at_newlines {
14309                this.change_selections(Default::default(), window, cx, |s| {
14310                    s.move_with(|_, sel| {
14311                        if sel.is_empty() {
14312                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14313                        }
14314                    });
14315                });
14316            }
14317            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14318            let item = this.cut_common(false, window, cx);
14319            cx.write_to_clipboard(item);
14320        });
14321    }
14322
14323    pub fn move_to_start_of_paragraph(
14324        &mut self,
14325        _: &MoveToStartOfParagraph,
14326        window: &mut Window,
14327        cx: &mut Context<Self>,
14328    ) {
14329        if matches!(self.mode, EditorMode::SingleLine) {
14330            cx.propagate();
14331            return;
14332        }
14333        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14334        self.change_selections(Default::default(), window, cx, |s| {
14335            s.move_with(|map, selection| {
14336                selection.collapse_to(
14337                    movement::start_of_paragraph(map, selection.head(), 1),
14338                    SelectionGoal::None,
14339                )
14340            });
14341        })
14342    }
14343
14344    pub fn move_to_end_of_paragraph(
14345        &mut self,
14346        _: &MoveToEndOfParagraph,
14347        window: &mut Window,
14348        cx: &mut Context<Self>,
14349    ) {
14350        if matches!(self.mode, EditorMode::SingleLine) {
14351            cx.propagate();
14352            return;
14353        }
14354        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14355        self.change_selections(Default::default(), window, cx, |s| {
14356            s.move_with(|map, selection| {
14357                selection.collapse_to(
14358                    movement::end_of_paragraph(map, selection.head(), 1),
14359                    SelectionGoal::None,
14360                )
14361            });
14362        })
14363    }
14364
14365    pub fn select_to_start_of_paragraph(
14366        &mut self,
14367        _: &SelectToStartOfParagraph,
14368        window: &mut Window,
14369        cx: &mut Context<Self>,
14370    ) {
14371        if matches!(self.mode, EditorMode::SingleLine) {
14372            cx.propagate();
14373            return;
14374        }
14375        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14376        self.change_selections(Default::default(), window, cx, |s| {
14377            s.move_heads_with(|map, head, _| {
14378                (
14379                    movement::start_of_paragraph(map, head, 1),
14380                    SelectionGoal::None,
14381                )
14382            });
14383        })
14384    }
14385
14386    pub fn select_to_end_of_paragraph(
14387        &mut self,
14388        _: &SelectToEndOfParagraph,
14389        window: &mut Window,
14390        cx: &mut Context<Self>,
14391    ) {
14392        if matches!(self.mode, EditorMode::SingleLine) {
14393            cx.propagate();
14394            return;
14395        }
14396        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14397        self.change_selections(Default::default(), window, cx, |s| {
14398            s.move_heads_with(|map, head, _| {
14399                (
14400                    movement::end_of_paragraph(map, head, 1),
14401                    SelectionGoal::None,
14402                )
14403            });
14404        })
14405    }
14406
14407    pub fn move_to_start_of_excerpt(
14408        &mut self,
14409        _: &MoveToStartOfExcerpt,
14410        window: &mut Window,
14411        cx: &mut Context<Self>,
14412    ) {
14413        if matches!(self.mode, EditorMode::SingleLine) {
14414            cx.propagate();
14415            return;
14416        }
14417        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14418        self.change_selections(Default::default(), window, cx, |s| {
14419            s.move_with(|map, selection| {
14420                selection.collapse_to(
14421                    movement::start_of_excerpt(
14422                        map,
14423                        selection.head(),
14424                        workspace::searchable::Direction::Prev,
14425                    ),
14426                    SelectionGoal::None,
14427                )
14428            });
14429        })
14430    }
14431
14432    pub fn move_to_start_of_next_excerpt(
14433        &mut self,
14434        _: &MoveToStartOfNextExcerpt,
14435        window: &mut Window,
14436        cx: &mut Context<Self>,
14437    ) {
14438        if matches!(self.mode, EditorMode::SingleLine) {
14439            cx.propagate();
14440            return;
14441        }
14442
14443        self.change_selections(Default::default(), window, cx, |s| {
14444            s.move_with(|map, selection| {
14445                selection.collapse_to(
14446                    movement::start_of_excerpt(
14447                        map,
14448                        selection.head(),
14449                        workspace::searchable::Direction::Next,
14450                    ),
14451                    SelectionGoal::None,
14452                )
14453            });
14454        })
14455    }
14456
14457    pub fn move_to_end_of_excerpt(
14458        &mut self,
14459        _: &MoveToEndOfExcerpt,
14460        window: &mut Window,
14461        cx: &mut Context<Self>,
14462    ) {
14463        if matches!(self.mode, EditorMode::SingleLine) {
14464            cx.propagate();
14465            return;
14466        }
14467        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14468        self.change_selections(Default::default(), window, cx, |s| {
14469            s.move_with(|map, selection| {
14470                selection.collapse_to(
14471                    movement::end_of_excerpt(
14472                        map,
14473                        selection.head(),
14474                        workspace::searchable::Direction::Next,
14475                    ),
14476                    SelectionGoal::None,
14477                )
14478            });
14479        })
14480    }
14481
14482    pub fn move_to_end_of_previous_excerpt(
14483        &mut self,
14484        _: &MoveToEndOfPreviousExcerpt,
14485        window: &mut Window,
14486        cx: &mut Context<Self>,
14487    ) {
14488        if matches!(self.mode, EditorMode::SingleLine) {
14489            cx.propagate();
14490            return;
14491        }
14492        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14493        self.change_selections(Default::default(), window, cx, |s| {
14494            s.move_with(|map, selection| {
14495                selection.collapse_to(
14496                    movement::end_of_excerpt(
14497                        map,
14498                        selection.head(),
14499                        workspace::searchable::Direction::Prev,
14500                    ),
14501                    SelectionGoal::None,
14502                )
14503            });
14504        })
14505    }
14506
14507    pub fn select_to_start_of_excerpt(
14508        &mut self,
14509        _: &SelectToStartOfExcerpt,
14510        window: &mut Window,
14511        cx: &mut Context<Self>,
14512    ) {
14513        if matches!(self.mode, EditorMode::SingleLine) {
14514            cx.propagate();
14515            return;
14516        }
14517        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14518        self.change_selections(Default::default(), window, cx, |s| {
14519            s.move_heads_with(|map, head, _| {
14520                (
14521                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14522                    SelectionGoal::None,
14523                )
14524            });
14525        })
14526    }
14527
14528    pub fn select_to_start_of_next_excerpt(
14529        &mut self,
14530        _: &SelectToStartOfNextExcerpt,
14531        window: &mut Window,
14532        cx: &mut Context<Self>,
14533    ) {
14534        if matches!(self.mode, EditorMode::SingleLine) {
14535            cx.propagate();
14536            return;
14537        }
14538        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14539        self.change_selections(Default::default(), window, cx, |s| {
14540            s.move_heads_with(|map, head, _| {
14541                (
14542                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14543                    SelectionGoal::None,
14544                )
14545            });
14546        })
14547    }
14548
14549    pub fn select_to_end_of_excerpt(
14550        &mut self,
14551        _: &SelectToEndOfExcerpt,
14552        window: &mut Window,
14553        cx: &mut Context<Self>,
14554    ) {
14555        if matches!(self.mode, EditorMode::SingleLine) {
14556            cx.propagate();
14557            return;
14558        }
14559        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14560        self.change_selections(Default::default(), window, cx, |s| {
14561            s.move_heads_with(|map, head, _| {
14562                (
14563                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14564                    SelectionGoal::None,
14565                )
14566            });
14567        })
14568    }
14569
14570    pub fn select_to_end_of_previous_excerpt(
14571        &mut self,
14572        _: &SelectToEndOfPreviousExcerpt,
14573        window: &mut Window,
14574        cx: &mut Context<Self>,
14575    ) {
14576        if matches!(self.mode, EditorMode::SingleLine) {
14577            cx.propagate();
14578            return;
14579        }
14580        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14581        self.change_selections(Default::default(), window, cx, |s| {
14582            s.move_heads_with(|map, head, _| {
14583                (
14584                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14585                    SelectionGoal::None,
14586                )
14587            });
14588        })
14589    }
14590
14591    pub fn move_to_beginning(
14592        &mut self,
14593        _: &MoveToBeginning,
14594        window: &mut Window,
14595        cx: &mut Context<Self>,
14596    ) {
14597        if matches!(self.mode, EditorMode::SingleLine) {
14598            cx.propagate();
14599            return;
14600        }
14601        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14602        self.change_selections(Default::default(), window, cx, |s| {
14603            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14604        });
14605    }
14606
14607    pub fn select_to_beginning(
14608        &mut self,
14609        _: &SelectToBeginning,
14610        window: &mut Window,
14611        cx: &mut Context<Self>,
14612    ) {
14613        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14614        selection.set_head(Point::zero(), SelectionGoal::None);
14615        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14616        self.change_selections(Default::default(), window, cx, |s| {
14617            s.select(vec![selection]);
14618        });
14619    }
14620
14621    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14622        if matches!(self.mode, EditorMode::SingleLine) {
14623            cx.propagate();
14624            return;
14625        }
14626        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14627        let cursor = self.buffer.read(cx).read(cx).len();
14628        self.change_selections(Default::default(), window, cx, |s| {
14629            s.select_ranges(vec![cursor..cursor])
14630        });
14631    }
14632
14633    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14634        self.nav_history = nav_history;
14635    }
14636
14637    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14638        self.nav_history.as_ref()
14639    }
14640
14641    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14642        self.push_to_nav_history(
14643            self.selections.newest_anchor().head(),
14644            None,
14645            false,
14646            true,
14647            cx,
14648        );
14649    }
14650
14651    fn push_to_nav_history(
14652        &mut self,
14653        cursor_anchor: Anchor,
14654        new_position: Option<Point>,
14655        is_deactivate: bool,
14656        always: bool,
14657        cx: &mut Context<Self>,
14658    ) {
14659        if let Some(nav_history) = self.nav_history.as_mut() {
14660            let buffer = self.buffer.read(cx).read(cx);
14661            let cursor_position = cursor_anchor.to_point(&buffer);
14662            let scroll_state = self.scroll_manager.anchor();
14663            let scroll_top_row = scroll_state.top_row(&buffer);
14664            drop(buffer);
14665
14666            if let Some(new_position) = new_position {
14667                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14668                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14669                    return;
14670                }
14671            }
14672
14673            nav_history.push(
14674                Some(NavigationData {
14675                    cursor_anchor,
14676                    cursor_position,
14677                    scroll_anchor: scroll_state,
14678                    scroll_top_row,
14679                }),
14680                cx,
14681            );
14682            cx.emit(EditorEvent::PushedToNavHistory {
14683                anchor: cursor_anchor,
14684                is_deactivate,
14685            })
14686        }
14687    }
14688
14689    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14690        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14691        let buffer = self.buffer.read(cx).snapshot(cx);
14692        let mut selection = self
14693            .selections
14694            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14695        selection.set_head(buffer.len(), SelectionGoal::None);
14696        self.change_selections(Default::default(), window, cx, |s| {
14697            s.select(vec![selection]);
14698        });
14699    }
14700
14701    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14702        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14703        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14704            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14705        });
14706    }
14707
14708    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14709        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14710        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14711        let mut selections = self.selections.all::<Point>(&display_map);
14712        let max_point = display_map.buffer_snapshot().max_point();
14713        for selection in &mut selections {
14714            let rows = selection.spanned_rows(true, &display_map);
14715            selection.start = Point::new(rows.start.0, 0);
14716            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14717            selection.reversed = false;
14718        }
14719        self.change_selections(Default::default(), window, cx, |s| {
14720            s.select(selections);
14721        });
14722    }
14723
14724    pub fn split_selection_into_lines(
14725        &mut self,
14726        action: &SplitSelectionIntoLines,
14727        window: &mut Window,
14728        cx: &mut Context<Self>,
14729    ) {
14730        let selections = self
14731            .selections
14732            .all::<Point>(&self.display_snapshot(cx))
14733            .into_iter()
14734            .map(|selection| selection.start..selection.end)
14735            .collect::<Vec<_>>();
14736        self.unfold_ranges(&selections, true, true, cx);
14737
14738        let mut new_selection_ranges = Vec::new();
14739        {
14740            let buffer = self.buffer.read(cx).read(cx);
14741            for selection in selections {
14742                for row in selection.start.row..selection.end.row {
14743                    let line_start = Point::new(row, 0);
14744                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14745
14746                    if action.keep_selections {
14747                        // Keep the selection range for each line
14748                        let selection_start = if row == selection.start.row {
14749                            selection.start
14750                        } else {
14751                            line_start
14752                        };
14753                        new_selection_ranges.push(selection_start..line_end);
14754                    } else {
14755                        // Collapse to cursor at end of line
14756                        new_selection_ranges.push(line_end..line_end);
14757                    }
14758                }
14759
14760                let is_multiline_selection = selection.start.row != selection.end.row;
14761                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14762                // so this action feels more ergonomic when paired with other selection operations
14763                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14764                if !should_skip_last {
14765                    if action.keep_selections {
14766                        if is_multiline_selection {
14767                            let line_start = Point::new(selection.end.row, 0);
14768                            new_selection_ranges.push(line_start..selection.end);
14769                        } else {
14770                            new_selection_ranges.push(selection.start..selection.end);
14771                        }
14772                    } else {
14773                        new_selection_ranges.push(selection.end..selection.end);
14774                    }
14775                }
14776            }
14777        }
14778        self.change_selections(Default::default(), window, cx, |s| {
14779            s.select_ranges(new_selection_ranges);
14780        });
14781    }
14782
14783    pub fn add_selection_above(
14784        &mut self,
14785        action: &AddSelectionAbove,
14786        window: &mut Window,
14787        cx: &mut Context<Self>,
14788    ) {
14789        self.add_selection(true, action.skip_soft_wrap, window, cx);
14790    }
14791
14792    pub fn add_selection_below(
14793        &mut self,
14794        action: &AddSelectionBelow,
14795        window: &mut Window,
14796        cx: &mut Context<Self>,
14797    ) {
14798        self.add_selection(false, action.skip_soft_wrap, window, cx);
14799    }
14800
14801    fn add_selection(
14802        &mut self,
14803        above: bool,
14804        skip_soft_wrap: bool,
14805        window: &mut Window,
14806        cx: &mut Context<Self>,
14807    ) {
14808        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14809
14810        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14811        let all_selections = self.selections.all::<Point>(&display_map);
14812        let text_layout_details = self.text_layout_details(window);
14813
14814        let (mut columnar_selections, new_selections_to_columnarize) = {
14815            if let Some(state) = self.add_selections_state.as_ref() {
14816                let columnar_selection_ids: HashSet<_> = state
14817                    .groups
14818                    .iter()
14819                    .flat_map(|group| group.stack.iter())
14820                    .copied()
14821                    .collect();
14822
14823                all_selections
14824                    .into_iter()
14825                    .partition(|s| columnar_selection_ids.contains(&s.id))
14826            } else {
14827                (Vec::new(), all_selections)
14828            }
14829        };
14830
14831        let mut state = self
14832            .add_selections_state
14833            .take()
14834            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14835
14836        for selection in new_selections_to_columnarize {
14837            let range = selection.display_range(&display_map).sorted();
14838            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14839            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14840            let positions = start_x.min(end_x)..start_x.max(end_x);
14841            let mut stack = Vec::new();
14842            for row in range.start.row().0..=range.end.row().0 {
14843                if let Some(selection) = self.selections.build_columnar_selection(
14844                    &display_map,
14845                    DisplayRow(row),
14846                    &positions,
14847                    selection.reversed,
14848                    &text_layout_details,
14849                ) {
14850                    stack.push(selection.id);
14851                    columnar_selections.push(selection);
14852                }
14853            }
14854            if !stack.is_empty() {
14855                if above {
14856                    stack.reverse();
14857                }
14858                state.groups.push(AddSelectionsGroup { above, stack });
14859            }
14860        }
14861
14862        let mut final_selections = Vec::new();
14863        let end_row = if above {
14864            DisplayRow(0)
14865        } else {
14866            display_map.max_point().row()
14867        };
14868
14869        let mut last_added_item_per_group = HashMap::default();
14870        for group in state.groups.iter_mut() {
14871            if let Some(last_id) = group.stack.last() {
14872                last_added_item_per_group.insert(*last_id, group);
14873            }
14874        }
14875
14876        for selection in columnar_selections {
14877            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14878                if above == group.above {
14879                    let range = selection.display_range(&display_map).sorted();
14880                    debug_assert_eq!(range.start.row(), range.end.row());
14881                    let mut row = range.start.row();
14882                    let positions =
14883                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14884                            Pixels::from(start)..Pixels::from(end)
14885                        } else {
14886                            let start_x =
14887                                display_map.x_for_display_point(range.start, &text_layout_details);
14888                            let end_x =
14889                                display_map.x_for_display_point(range.end, &text_layout_details);
14890                            start_x.min(end_x)..start_x.max(end_x)
14891                        };
14892
14893                    let mut maybe_new_selection = None;
14894                    let direction = if above { -1 } else { 1 };
14895
14896                    while row != end_row {
14897                        if skip_soft_wrap {
14898                            row = display_map
14899                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14900                                .row();
14901                        } else if above {
14902                            row.0 -= 1;
14903                        } else {
14904                            row.0 += 1;
14905                        }
14906
14907                        if let Some(new_selection) = self.selections.build_columnar_selection(
14908                            &display_map,
14909                            row,
14910                            &positions,
14911                            selection.reversed,
14912                            &text_layout_details,
14913                        ) {
14914                            maybe_new_selection = Some(new_selection);
14915                            break;
14916                        }
14917                    }
14918
14919                    if let Some(new_selection) = maybe_new_selection {
14920                        group.stack.push(new_selection.id);
14921                        if above {
14922                            final_selections.push(new_selection);
14923                            final_selections.push(selection);
14924                        } else {
14925                            final_selections.push(selection);
14926                            final_selections.push(new_selection);
14927                        }
14928                    } else {
14929                        final_selections.push(selection);
14930                    }
14931                } else {
14932                    group.stack.pop();
14933                }
14934            } else {
14935                final_selections.push(selection);
14936            }
14937        }
14938
14939        self.change_selections(Default::default(), window, cx, |s| {
14940            s.select(final_selections);
14941        });
14942
14943        let final_selection_ids: HashSet<_> = self
14944            .selections
14945            .all::<Point>(&display_map)
14946            .iter()
14947            .map(|s| s.id)
14948            .collect();
14949        state.groups.retain_mut(|group| {
14950            // selections might get merged above so we remove invalid items from stacks
14951            group.stack.retain(|id| final_selection_ids.contains(id));
14952
14953            // single selection in stack can be treated as initial state
14954            group.stack.len() > 1
14955        });
14956
14957        if !state.groups.is_empty() {
14958            self.add_selections_state = Some(state);
14959        }
14960    }
14961
14962    pub fn insert_snippet_at_selections(
14963        &mut self,
14964        action: &InsertSnippet,
14965        window: &mut Window,
14966        cx: &mut Context<Self>,
14967    ) {
14968        self.try_insert_snippet_at_selections(action, window, cx)
14969            .log_err();
14970    }
14971
14972    fn try_insert_snippet_at_selections(
14973        &mut self,
14974        action: &InsertSnippet,
14975        window: &mut Window,
14976        cx: &mut Context<Self>,
14977    ) -> Result<()> {
14978        let insertion_ranges = self
14979            .selections
14980            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
14981            .into_iter()
14982            .map(|selection| selection.range())
14983            .collect_vec();
14984
14985        let snippet = if let Some(snippet_body) = &action.snippet {
14986            if action.language.is_none() && action.name.is_none() {
14987                Snippet::parse(snippet_body)?
14988            } else {
14989                bail!("`snippet` is mutually exclusive with `language` and `name`")
14990            }
14991        } else if let Some(name) = &action.name {
14992            let project = self.project().context("no project")?;
14993            let snippet_store = project.read(cx).snippets().read(cx);
14994            let snippet = snippet_store
14995                .snippets_for(action.language.clone(), cx)
14996                .into_iter()
14997                .find(|snippet| snippet.name == *name)
14998                .context("snippet not found")?;
14999            Snippet::parse(&snippet.body)?
15000        } else {
15001            // todo(andrew): open modal to select snippet
15002            bail!("`name` or `snippet` is required")
15003        };
15004
15005        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15006    }
15007
15008    fn select_match_ranges(
15009        &mut self,
15010        range: Range<MultiBufferOffset>,
15011        reversed: bool,
15012        replace_newest: bool,
15013        auto_scroll: Option<Autoscroll>,
15014        window: &mut Window,
15015        cx: &mut Context<Editor>,
15016    ) {
15017        self.unfold_ranges(
15018            std::slice::from_ref(&range),
15019            false,
15020            auto_scroll.is_some(),
15021            cx,
15022        );
15023        let effects = if let Some(scroll) = auto_scroll {
15024            SelectionEffects::scroll(scroll)
15025        } else {
15026            SelectionEffects::no_scroll()
15027        };
15028        self.change_selections(effects, window, cx, |s| {
15029            if replace_newest {
15030                s.delete(s.newest_anchor().id);
15031            }
15032            if reversed {
15033                s.insert_range(range.end..range.start);
15034            } else {
15035                s.insert_range(range);
15036            }
15037        });
15038    }
15039
15040    pub fn select_next_match_internal(
15041        &mut self,
15042        display_map: &DisplaySnapshot,
15043        replace_newest: bool,
15044        autoscroll: Option<Autoscroll>,
15045        window: &mut Window,
15046        cx: &mut Context<Self>,
15047    ) -> Result<()> {
15048        let buffer = display_map.buffer_snapshot();
15049        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15050        if let Some(mut select_next_state) = self.select_next_state.take() {
15051            let query = &select_next_state.query;
15052            if !select_next_state.done {
15053                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15054                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15055                let mut next_selected_range = None;
15056
15057                let bytes_after_last_selection =
15058                    buffer.bytes_in_range(last_selection.end..buffer.len());
15059                let bytes_before_first_selection =
15060                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15061                let query_matches = query
15062                    .stream_find_iter(bytes_after_last_selection)
15063                    .map(|result| (last_selection.end, result))
15064                    .chain(
15065                        query
15066                            .stream_find_iter(bytes_before_first_selection)
15067                            .map(|result| (MultiBufferOffset(0), result)),
15068                    );
15069
15070                for (start_offset, query_match) in query_matches {
15071                    let query_match = query_match.unwrap(); // can only fail due to I/O
15072                    let offset_range =
15073                        start_offset + query_match.start()..start_offset + query_match.end();
15074
15075                    if !select_next_state.wordwise
15076                        || (!buffer.is_inside_word(offset_range.start, None)
15077                            && !buffer.is_inside_word(offset_range.end, None))
15078                    {
15079                        let idx = selections
15080                            .partition_point(|selection| selection.end <= offset_range.start);
15081                        let overlaps = selections
15082                            .get(idx)
15083                            .map_or(false, |selection| selection.start < offset_range.end);
15084
15085                        if !overlaps {
15086                            next_selected_range = Some(offset_range);
15087                            break;
15088                        }
15089                    }
15090                }
15091
15092                if let Some(next_selected_range) = next_selected_range {
15093                    self.select_match_ranges(
15094                        next_selected_range,
15095                        last_selection.reversed,
15096                        replace_newest,
15097                        autoscroll,
15098                        window,
15099                        cx,
15100                    );
15101                } else {
15102                    select_next_state.done = true;
15103                }
15104            }
15105
15106            self.select_next_state = Some(select_next_state);
15107        } else {
15108            let mut only_carets = true;
15109            let mut same_text_selected = true;
15110            let mut selected_text = None;
15111
15112            let mut selections_iter = selections.iter().peekable();
15113            while let Some(selection) = selections_iter.next() {
15114                if selection.start != selection.end {
15115                    only_carets = false;
15116                }
15117
15118                if same_text_selected {
15119                    if selected_text.is_none() {
15120                        selected_text =
15121                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15122                    }
15123
15124                    if let Some(next_selection) = selections_iter.peek() {
15125                        if next_selection.len() == selection.len() {
15126                            let next_selected_text = buffer
15127                                .text_for_range(next_selection.range())
15128                                .collect::<String>();
15129                            if Some(next_selected_text) != selected_text {
15130                                same_text_selected = false;
15131                                selected_text = None;
15132                            }
15133                        } else {
15134                            same_text_selected = false;
15135                            selected_text = None;
15136                        }
15137                    }
15138                }
15139            }
15140
15141            if only_carets {
15142                for selection in &mut selections {
15143                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15144                    selection.start = word_range.start;
15145                    selection.end = word_range.end;
15146                    selection.goal = SelectionGoal::None;
15147                    selection.reversed = false;
15148                    self.select_match_ranges(
15149                        selection.start..selection.end,
15150                        selection.reversed,
15151                        replace_newest,
15152                        autoscroll,
15153                        window,
15154                        cx,
15155                    );
15156                }
15157
15158                if selections.len() == 1 {
15159                    let selection = selections
15160                        .last()
15161                        .expect("ensured that there's only one selection");
15162                    let query = buffer
15163                        .text_for_range(selection.start..selection.end)
15164                        .collect::<String>();
15165                    let is_empty = query.is_empty();
15166                    let select_state = SelectNextState {
15167                        query: self.build_query(&[query], cx)?,
15168                        wordwise: true,
15169                        done: is_empty,
15170                    };
15171                    self.select_next_state = Some(select_state);
15172                } else {
15173                    self.select_next_state = None;
15174                }
15175            } else if let Some(selected_text) = selected_text {
15176                self.select_next_state = Some(SelectNextState {
15177                    query: self.build_query(&[selected_text], cx)?,
15178                    wordwise: false,
15179                    done: false,
15180                });
15181                self.select_next_match_internal(
15182                    display_map,
15183                    replace_newest,
15184                    autoscroll,
15185                    window,
15186                    cx,
15187                )?;
15188            }
15189        }
15190        Ok(())
15191    }
15192
15193    pub fn select_all_matches(
15194        &mut self,
15195        _action: &SelectAllMatches,
15196        window: &mut Window,
15197        cx: &mut Context<Self>,
15198    ) -> Result<()> {
15199        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15200
15201        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15202
15203        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15204        let Some(select_next_state) = self.select_next_state.as_mut() else {
15205            return Ok(());
15206        };
15207        if select_next_state.done {
15208            return Ok(());
15209        }
15210
15211        let mut new_selections = Vec::new();
15212
15213        let reversed = self
15214            .selections
15215            .oldest::<MultiBufferOffset>(&display_map)
15216            .reversed;
15217        let buffer = display_map.buffer_snapshot();
15218        let query_matches = select_next_state
15219            .query
15220            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15221
15222        for query_match in query_matches.into_iter() {
15223            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15224            let offset_range = if reversed {
15225                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15226            } else {
15227                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15228            };
15229
15230            if !select_next_state.wordwise
15231                || (!buffer.is_inside_word(offset_range.start, None)
15232                    && !buffer.is_inside_word(offset_range.end, None))
15233            {
15234                new_selections.push(offset_range.start..offset_range.end);
15235            }
15236        }
15237
15238        select_next_state.done = true;
15239
15240        if new_selections.is_empty() {
15241            log::error!("bug: new_selections is empty in select_all_matches");
15242            return Ok(());
15243        }
15244
15245        self.unfold_ranges(&new_selections.clone(), false, false, cx);
15246        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15247            selections.select_ranges(new_selections)
15248        });
15249
15250        Ok(())
15251    }
15252
15253    pub fn select_next(
15254        &mut self,
15255        action: &SelectNext,
15256        window: &mut Window,
15257        cx: &mut Context<Self>,
15258    ) -> Result<()> {
15259        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15260        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15261        self.select_next_match_internal(
15262            &display_map,
15263            action.replace_newest,
15264            Some(Autoscroll::newest()),
15265            window,
15266            cx,
15267        )?;
15268        Ok(())
15269    }
15270
15271    pub fn select_previous(
15272        &mut self,
15273        action: &SelectPrevious,
15274        window: &mut Window,
15275        cx: &mut Context<Self>,
15276    ) -> Result<()> {
15277        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15278        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15279        let buffer = display_map.buffer_snapshot();
15280        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15281        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15282            let query = &select_prev_state.query;
15283            if !select_prev_state.done {
15284                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15285                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15286                let mut next_selected_range = None;
15287                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15288                let bytes_before_last_selection =
15289                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15290                let bytes_after_first_selection =
15291                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15292                let query_matches = query
15293                    .stream_find_iter(bytes_before_last_selection)
15294                    .map(|result| (last_selection.start, result))
15295                    .chain(
15296                        query
15297                            .stream_find_iter(bytes_after_first_selection)
15298                            .map(|result| (buffer.len(), result)),
15299                    );
15300                for (end_offset, query_match) in query_matches {
15301                    let query_match = query_match.unwrap(); // can only fail due to I/O
15302                    let offset_range =
15303                        end_offset - query_match.end()..end_offset - query_match.start();
15304
15305                    if !select_prev_state.wordwise
15306                        || (!buffer.is_inside_word(offset_range.start, None)
15307                            && !buffer.is_inside_word(offset_range.end, None))
15308                    {
15309                        next_selected_range = Some(offset_range);
15310                        break;
15311                    }
15312                }
15313
15314                if let Some(next_selected_range) = next_selected_range {
15315                    self.select_match_ranges(
15316                        next_selected_range,
15317                        last_selection.reversed,
15318                        action.replace_newest,
15319                        Some(Autoscroll::newest()),
15320                        window,
15321                        cx,
15322                    );
15323                } else {
15324                    select_prev_state.done = true;
15325                }
15326            }
15327
15328            self.select_prev_state = Some(select_prev_state);
15329        } else {
15330            let mut only_carets = true;
15331            let mut same_text_selected = true;
15332            let mut selected_text = None;
15333
15334            let mut selections_iter = selections.iter().peekable();
15335            while let Some(selection) = selections_iter.next() {
15336                if selection.start != selection.end {
15337                    only_carets = false;
15338                }
15339
15340                if same_text_selected {
15341                    if selected_text.is_none() {
15342                        selected_text =
15343                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15344                    }
15345
15346                    if let Some(next_selection) = selections_iter.peek() {
15347                        if next_selection.len() == selection.len() {
15348                            let next_selected_text = buffer
15349                                .text_for_range(next_selection.range())
15350                                .collect::<String>();
15351                            if Some(next_selected_text) != selected_text {
15352                                same_text_selected = false;
15353                                selected_text = None;
15354                            }
15355                        } else {
15356                            same_text_selected = false;
15357                            selected_text = None;
15358                        }
15359                    }
15360                }
15361            }
15362
15363            if only_carets {
15364                for selection in &mut selections {
15365                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15366                    selection.start = word_range.start;
15367                    selection.end = word_range.end;
15368                    selection.goal = SelectionGoal::None;
15369                    selection.reversed = false;
15370                    self.select_match_ranges(
15371                        selection.start..selection.end,
15372                        selection.reversed,
15373                        action.replace_newest,
15374                        Some(Autoscroll::newest()),
15375                        window,
15376                        cx,
15377                    );
15378                }
15379                if selections.len() == 1 {
15380                    let selection = selections
15381                        .last()
15382                        .expect("ensured that there's only one selection");
15383                    let query = buffer
15384                        .text_for_range(selection.start..selection.end)
15385                        .collect::<String>();
15386                    let is_empty = query.is_empty();
15387                    let select_state = SelectNextState {
15388                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15389                        wordwise: true,
15390                        done: is_empty,
15391                    };
15392                    self.select_prev_state = Some(select_state);
15393                } else {
15394                    self.select_prev_state = None;
15395                }
15396            } else if let Some(selected_text) = selected_text {
15397                self.select_prev_state = Some(SelectNextState {
15398                    query: self
15399                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15400                    wordwise: false,
15401                    done: false,
15402                });
15403                self.select_previous(action, window, cx)?;
15404            }
15405        }
15406        Ok(())
15407    }
15408
15409    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15410    /// setting the case sensitivity based on the global
15411    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15412    /// editor's settings.
15413    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15414    where
15415        I: IntoIterator<Item = P>,
15416        P: AsRef<[u8]>,
15417    {
15418        let case_sensitive = self
15419            .select_next_is_case_sensitive
15420            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
15421
15422        let mut builder = AhoCorasickBuilder::new();
15423        builder.ascii_case_insensitive(!case_sensitive);
15424        builder.build(patterns)
15425    }
15426
15427    pub fn find_next_match(
15428        &mut self,
15429        _: &FindNextMatch,
15430        window: &mut Window,
15431        cx: &mut Context<Self>,
15432    ) -> Result<()> {
15433        let selections = self.selections.disjoint_anchors_arc();
15434        match selections.first() {
15435            Some(first) if selections.len() >= 2 => {
15436                self.change_selections(Default::default(), window, cx, |s| {
15437                    s.select_ranges([first.range()]);
15438                });
15439            }
15440            _ => self.select_next(
15441                &SelectNext {
15442                    replace_newest: true,
15443                },
15444                window,
15445                cx,
15446            )?,
15447        }
15448        Ok(())
15449    }
15450
15451    pub fn find_previous_match(
15452        &mut self,
15453        _: &FindPreviousMatch,
15454        window: &mut Window,
15455        cx: &mut Context<Self>,
15456    ) -> Result<()> {
15457        let selections = self.selections.disjoint_anchors_arc();
15458        match selections.last() {
15459            Some(last) if selections.len() >= 2 => {
15460                self.change_selections(Default::default(), window, cx, |s| {
15461                    s.select_ranges([last.range()]);
15462                });
15463            }
15464            _ => self.select_previous(
15465                &SelectPrevious {
15466                    replace_newest: true,
15467                },
15468                window,
15469                cx,
15470            )?,
15471        }
15472        Ok(())
15473    }
15474
15475    pub fn toggle_comments(
15476        &mut self,
15477        action: &ToggleComments,
15478        window: &mut Window,
15479        cx: &mut Context<Self>,
15480    ) {
15481        if self.read_only(cx) {
15482            return;
15483        }
15484        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15485        let text_layout_details = &self.text_layout_details(window);
15486        self.transact(window, cx, |this, window, cx| {
15487            let mut selections = this
15488                .selections
15489                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15490            let mut edits = Vec::new();
15491            let mut selection_edit_ranges = Vec::new();
15492            let mut last_toggled_row = None;
15493            let snapshot = this.buffer.read(cx).read(cx);
15494            let empty_str: Arc<str> = Arc::default();
15495            let mut suffixes_inserted = Vec::new();
15496            let ignore_indent = action.ignore_indent;
15497
15498            fn comment_prefix_range(
15499                snapshot: &MultiBufferSnapshot,
15500                row: MultiBufferRow,
15501                comment_prefix: &str,
15502                comment_prefix_whitespace: &str,
15503                ignore_indent: bool,
15504            ) -> Range<Point> {
15505                let indent_size = if ignore_indent {
15506                    0
15507                } else {
15508                    snapshot.indent_size_for_line(row).len
15509                };
15510
15511                let start = Point::new(row.0, indent_size);
15512
15513                let mut line_bytes = snapshot
15514                    .bytes_in_range(start..snapshot.max_point())
15515                    .flatten()
15516                    .copied();
15517
15518                // If this line currently begins with the line comment prefix, then record
15519                // the range containing the prefix.
15520                if line_bytes
15521                    .by_ref()
15522                    .take(comment_prefix.len())
15523                    .eq(comment_prefix.bytes())
15524                {
15525                    // Include any whitespace that matches the comment prefix.
15526                    let matching_whitespace_len = line_bytes
15527                        .zip(comment_prefix_whitespace.bytes())
15528                        .take_while(|(a, b)| a == b)
15529                        .count() as u32;
15530                    let end = Point::new(
15531                        start.row,
15532                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15533                    );
15534                    start..end
15535                } else {
15536                    start..start
15537                }
15538            }
15539
15540            fn comment_suffix_range(
15541                snapshot: &MultiBufferSnapshot,
15542                row: MultiBufferRow,
15543                comment_suffix: &str,
15544                comment_suffix_has_leading_space: bool,
15545            ) -> Range<Point> {
15546                let end = Point::new(row.0, snapshot.line_len(row));
15547                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15548
15549                let mut line_end_bytes = snapshot
15550                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15551                    .flatten()
15552                    .copied();
15553
15554                let leading_space_len = if suffix_start_column > 0
15555                    && line_end_bytes.next() == Some(b' ')
15556                    && comment_suffix_has_leading_space
15557                {
15558                    1
15559                } else {
15560                    0
15561                };
15562
15563                // If this line currently begins with the line comment prefix, then record
15564                // the range containing the prefix.
15565                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15566                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15567                    start..end
15568                } else {
15569                    end..end
15570                }
15571            }
15572
15573            // TODO: Handle selections that cross excerpts
15574            for selection in &mut selections {
15575                let start_column = snapshot
15576                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15577                    .len;
15578                let language = if let Some(language) =
15579                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15580                {
15581                    language
15582                } else {
15583                    continue;
15584                };
15585
15586                selection_edit_ranges.clear();
15587
15588                // If multiple selections contain a given row, avoid processing that
15589                // row more than once.
15590                let mut start_row = MultiBufferRow(selection.start.row);
15591                if last_toggled_row == Some(start_row) {
15592                    start_row = start_row.next_row();
15593                }
15594                let end_row =
15595                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15596                        MultiBufferRow(selection.end.row - 1)
15597                    } else {
15598                        MultiBufferRow(selection.end.row)
15599                    };
15600                last_toggled_row = Some(end_row);
15601
15602                if start_row > end_row {
15603                    continue;
15604                }
15605
15606                // If the language has line comments, toggle those.
15607                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15608
15609                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15610                if ignore_indent {
15611                    full_comment_prefixes = full_comment_prefixes
15612                        .into_iter()
15613                        .map(|s| Arc::from(s.trim_end()))
15614                        .collect();
15615                }
15616
15617                if !full_comment_prefixes.is_empty() {
15618                    let first_prefix = full_comment_prefixes
15619                        .first()
15620                        .expect("prefixes is non-empty");
15621                    let prefix_trimmed_lengths = full_comment_prefixes
15622                        .iter()
15623                        .map(|p| p.trim_end_matches(' ').len())
15624                        .collect::<SmallVec<[usize; 4]>>();
15625
15626                    let mut all_selection_lines_are_comments = true;
15627
15628                    for row in start_row.0..=end_row.0 {
15629                        let row = MultiBufferRow(row);
15630                        if start_row < end_row && snapshot.is_line_blank(row) {
15631                            continue;
15632                        }
15633
15634                        let prefix_range = full_comment_prefixes
15635                            .iter()
15636                            .zip(prefix_trimmed_lengths.iter().copied())
15637                            .map(|(prefix, trimmed_prefix_len)| {
15638                                comment_prefix_range(
15639                                    snapshot.deref(),
15640                                    row,
15641                                    &prefix[..trimmed_prefix_len],
15642                                    &prefix[trimmed_prefix_len..],
15643                                    ignore_indent,
15644                                )
15645                            })
15646                            .max_by_key(|range| range.end.column - range.start.column)
15647                            .expect("prefixes is non-empty");
15648
15649                        if prefix_range.is_empty() {
15650                            all_selection_lines_are_comments = false;
15651                        }
15652
15653                        selection_edit_ranges.push(prefix_range);
15654                    }
15655
15656                    if all_selection_lines_are_comments {
15657                        edits.extend(
15658                            selection_edit_ranges
15659                                .iter()
15660                                .cloned()
15661                                .map(|range| (range, empty_str.clone())),
15662                        );
15663                    } else {
15664                        let min_column = selection_edit_ranges
15665                            .iter()
15666                            .map(|range| range.start.column)
15667                            .min()
15668                            .unwrap_or(0);
15669                        edits.extend(selection_edit_ranges.iter().map(|range| {
15670                            let position = Point::new(range.start.row, min_column);
15671                            (position..position, first_prefix.clone())
15672                        }));
15673                    }
15674                } else if let Some(BlockCommentConfig {
15675                    start: full_comment_prefix,
15676                    end: comment_suffix,
15677                    ..
15678                }) = language.block_comment()
15679                {
15680                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15681                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15682                    let prefix_range = comment_prefix_range(
15683                        snapshot.deref(),
15684                        start_row,
15685                        comment_prefix,
15686                        comment_prefix_whitespace,
15687                        ignore_indent,
15688                    );
15689                    let suffix_range = comment_suffix_range(
15690                        snapshot.deref(),
15691                        end_row,
15692                        comment_suffix.trim_start_matches(' '),
15693                        comment_suffix.starts_with(' '),
15694                    );
15695
15696                    if prefix_range.is_empty() || suffix_range.is_empty() {
15697                        edits.push((
15698                            prefix_range.start..prefix_range.start,
15699                            full_comment_prefix.clone(),
15700                        ));
15701                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15702                        suffixes_inserted.push((end_row, comment_suffix.len()));
15703                    } else {
15704                        edits.push((prefix_range, empty_str.clone()));
15705                        edits.push((suffix_range, empty_str.clone()));
15706                    }
15707                } else {
15708                    continue;
15709                }
15710            }
15711
15712            drop(snapshot);
15713            this.buffer.update(cx, |buffer, cx| {
15714                buffer.edit(edits, None, cx);
15715            });
15716
15717            // Adjust selections so that they end before any comment suffixes that
15718            // were inserted.
15719            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15720            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15721            let snapshot = this.buffer.read(cx).read(cx);
15722            for selection in &mut selections {
15723                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15724                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15725                        Ordering::Less => {
15726                            suffixes_inserted.next();
15727                            continue;
15728                        }
15729                        Ordering::Greater => break,
15730                        Ordering::Equal => {
15731                            if selection.end.column == snapshot.line_len(row) {
15732                                if selection.is_empty() {
15733                                    selection.start.column -= suffix_len as u32;
15734                                }
15735                                selection.end.column -= suffix_len as u32;
15736                            }
15737                            break;
15738                        }
15739                    }
15740                }
15741            }
15742
15743            drop(snapshot);
15744            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15745
15746            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15747            let selections_on_single_row = selections.windows(2).all(|selections| {
15748                selections[0].start.row == selections[1].start.row
15749                    && selections[0].end.row == selections[1].end.row
15750                    && selections[0].start.row == selections[0].end.row
15751            });
15752            let selections_selecting = selections
15753                .iter()
15754                .any(|selection| selection.start != selection.end);
15755            let advance_downwards = action.advance_downwards
15756                && selections_on_single_row
15757                && !selections_selecting
15758                && !matches!(this.mode, EditorMode::SingleLine);
15759
15760            if advance_downwards {
15761                let snapshot = this.buffer.read(cx).snapshot(cx);
15762
15763                this.change_selections(Default::default(), window, cx, |s| {
15764                    s.move_cursors_with(|display_snapshot, display_point, _| {
15765                        let mut point = display_point.to_point(display_snapshot);
15766                        point.row += 1;
15767                        point = snapshot.clip_point(point, Bias::Left);
15768                        let display_point = point.to_display_point(display_snapshot);
15769                        let goal = SelectionGoal::HorizontalPosition(
15770                            display_snapshot
15771                                .x_for_display_point(display_point, text_layout_details)
15772                                .into(),
15773                        );
15774                        (display_point, goal)
15775                    })
15776                });
15777            }
15778        });
15779    }
15780
15781    pub fn select_enclosing_symbol(
15782        &mut self,
15783        _: &SelectEnclosingSymbol,
15784        window: &mut Window,
15785        cx: &mut Context<Self>,
15786    ) {
15787        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15788
15789        let buffer = self.buffer.read(cx).snapshot(cx);
15790        let old_selections = self
15791            .selections
15792            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15793            .into_boxed_slice();
15794
15795        fn update_selection(
15796            selection: &Selection<MultiBufferOffset>,
15797            buffer_snap: &MultiBufferSnapshot,
15798        ) -> Option<Selection<MultiBufferOffset>> {
15799            let cursor = selection.head();
15800            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15801            for symbol in symbols.iter().rev() {
15802                let start = symbol.range.start.to_offset(buffer_snap);
15803                let end = symbol.range.end.to_offset(buffer_snap);
15804                let new_range = start..end;
15805                if start < selection.start || end > selection.end {
15806                    return Some(Selection {
15807                        id: selection.id,
15808                        start: new_range.start,
15809                        end: new_range.end,
15810                        goal: SelectionGoal::None,
15811                        reversed: selection.reversed,
15812                    });
15813                }
15814            }
15815            None
15816        }
15817
15818        let mut selected_larger_symbol = false;
15819        let new_selections = old_selections
15820            .iter()
15821            .map(|selection| match update_selection(selection, &buffer) {
15822                Some(new_selection) => {
15823                    if new_selection.range() != selection.range() {
15824                        selected_larger_symbol = true;
15825                    }
15826                    new_selection
15827                }
15828                None => selection.clone(),
15829            })
15830            .collect::<Vec<_>>();
15831
15832        if selected_larger_symbol {
15833            self.change_selections(Default::default(), window, cx, |s| {
15834                s.select(new_selections);
15835            });
15836        }
15837    }
15838
15839    pub fn select_larger_syntax_node(
15840        &mut self,
15841        _: &SelectLargerSyntaxNode,
15842        window: &mut Window,
15843        cx: &mut Context<Self>,
15844    ) {
15845        let Some(visible_row_count) = self.visible_row_count() else {
15846            return;
15847        };
15848        let old_selections: Box<[_]> = self
15849            .selections
15850            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15851            .into();
15852        if old_selections.is_empty() {
15853            return;
15854        }
15855
15856        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15857
15858        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15859        let buffer = self.buffer.read(cx).snapshot(cx);
15860
15861        let mut selected_larger_node = false;
15862        let mut new_selections = old_selections
15863            .iter()
15864            .map(|selection| {
15865                let old_range = selection.start..selection.end;
15866
15867                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15868                    // manually select word at selection
15869                    if ["string_content", "inline"].contains(&node.kind()) {
15870                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15871                        // ignore if word is already selected
15872                        if !word_range.is_empty() && old_range != word_range {
15873                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15874                            // only select word if start and end point belongs to same word
15875                            if word_range == last_word_range {
15876                                selected_larger_node = true;
15877                                return Selection {
15878                                    id: selection.id,
15879                                    start: word_range.start,
15880                                    end: word_range.end,
15881                                    goal: SelectionGoal::None,
15882                                    reversed: selection.reversed,
15883                                };
15884                            }
15885                        }
15886                    }
15887                }
15888
15889                let mut new_range = old_range.clone();
15890                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15891                    new_range = range;
15892                    if !node.is_named() {
15893                        continue;
15894                    }
15895                    if !display_map.intersects_fold(new_range.start)
15896                        && !display_map.intersects_fold(new_range.end)
15897                    {
15898                        break;
15899                    }
15900                }
15901
15902                selected_larger_node |= new_range != old_range;
15903                Selection {
15904                    id: selection.id,
15905                    start: new_range.start,
15906                    end: new_range.end,
15907                    goal: SelectionGoal::None,
15908                    reversed: selection.reversed,
15909                }
15910            })
15911            .collect::<Vec<_>>();
15912
15913        if !selected_larger_node {
15914            return; // don't put this call in the history
15915        }
15916
15917        // scroll based on transformation done to the last selection created by the user
15918        let (last_old, last_new) = old_selections
15919            .last()
15920            .zip(new_selections.last().cloned())
15921            .expect("old_selections isn't empty");
15922
15923        // revert selection
15924        let is_selection_reversed = {
15925            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15926            new_selections.last_mut().expect("checked above").reversed =
15927                should_newest_selection_be_reversed;
15928            should_newest_selection_be_reversed
15929        };
15930
15931        if selected_larger_node {
15932            self.select_syntax_node_history.disable_clearing = true;
15933            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15934                s.select(new_selections.clone());
15935            });
15936            self.select_syntax_node_history.disable_clearing = false;
15937        }
15938
15939        let start_row = last_new.start.to_display_point(&display_map).row().0;
15940        let end_row = last_new.end.to_display_point(&display_map).row().0;
15941        let selection_height = end_row - start_row + 1;
15942        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15943
15944        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15945        let scroll_behavior = if fits_on_the_screen {
15946            self.request_autoscroll(Autoscroll::fit(), cx);
15947            SelectSyntaxNodeScrollBehavior::FitSelection
15948        } else if is_selection_reversed {
15949            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15950            SelectSyntaxNodeScrollBehavior::CursorTop
15951        } else {
15952            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15953            SelectSyntaxNodeScrollBehavior::CursorBottom
15954        };
15955
15956        self.select_syntax_node_history.push((
15957            old_selections,
15958            scroll_behavior,
15959            is_selection_reversed,
15960        ));
15961    }
15962
15963    pub fn select_smaller_syntax_node(
15964        &mut self,
15965        _: &SelectSmallerSyntaxNode,
15966        window: &mut Window,
15967        cx: &mut Context<Self>,
15968    ) {
15969        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15970
15971        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15972            self.select_syntax_node_history.pop()
15973        {
15974            if let Some(selection) = selections.last_mut() {
15975                selection.reversed = is_selection_reversed;
15976            }
15977
15978            self.select_syntax_node_history.disable_clearing = true;
15979            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15980                s.select(selections.to_vec());
15981            });
15982            self.select_syntax_node_history.disable_clearing = false;
15983
15984            match scroll_behavior {
15985                SelectSyntaxNodeScrollBehavior::CursorTop => {
15986                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15987                }
15988                SelectSyntaxNodeScrollBehavior::FitSelection => {
15989                    self.request_autoscroll(Autoscroll::fit(), cx);
15990                }
15991                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15992                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15993                }
15994            }
15995        }
15996    }
15997
15998    pub fn unwrap_syntax_node(
15999        &mut self,
16000        _: &UnwrapSyntaxNode,
16001        window: &mut Window,
16002        cx: &mut Context<Self>,
16003    ) {
16004        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16005
16006        let buffer = self.buffer.read(cx).snapshot(cx);
16007        let selections = self
16008            .selections
16009            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16010            .into_iter()
16011            // subtracting the offset requires sorting
16012            .sorted_by_key(|i| i.start);
16013
16014        let full_edits = selections
16015            .into_iter()
16016            .filter_map(|selection| {
16017                let child = if selection.is_empty()
16018                    && let Some((_, ancestor_range)) =
16019                        buffer.syntax_ancestor(selection.start..selection.end)
16020                {
16021                    ancestor_range
16022                } else {
16023                    selection.range()
16024                };
16025
16026                let mut parent = child.clone();
16027                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16028                    parent = ancestor_range;
16029                    if parent.start < child.start || parent.end > child.end {
16030                        break;
16031                    }
16032                }
16033
16034                if parent == child {
16035                    return None;
16036                }
16037                let text = buffer.text_for_range(child).collect::<String>();
16038                Some((selection.id, parent, text))
16039            })
16040            .collect::<Vec<_>>();
16041        if full_edits.is_empty() {
16042            return;
16043        }
16044
16045        self.transact(window, cx, |this, window, cx| {
16046            this.buffer.update(cx, |buffer, cx| {
16047                buffer.edit(
16048                    full_edits
16049                        .iter()
16050                        .map(|(_, p, t)| (p.clone(), t.clone()))
16051                        .collect::<Vec<_>>(),
16052                    None,
16053                    cx,
16054                );
16055            });
16056            this.change_selections(Default::default(), window, cx, |s| {
16057                let mut offset = 0;
16058                let mut selections = vec![];
16059                for (id, parent, text) in full_edits {
16060                    let start = parent.start - offset;
16061                    offset += (parent.end - parent.start) - text.len();
16062                    selections.push(Selection {
16063                        id,
16064                        start,
16065                        end: start + text.len(),
16066                        reversed: false,
16067                        goal: Default::default(),
16068                    });
16069                }
16070                s.select(selections);
16071            });
16072        });
16073    }
16074
16075    pub fn select_next_syntax_node(
16076        &mut self,
16077        _: &SelectNextSyntaxNode,
16078        window: &mut Window,
16079        cx: &mut Context<Self>,
16080    ) {
16081        let old_selections: Box<[_]> = self
16082            .selections
16083            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16084            .into();
16085        if old_selections.is_empty() {
16086            return;
16087        }
16088
16089        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16090
16091        let buffer = self.buffer.read(cx).snapshot(cx);
16092        let mut selected_sibling = false;
16093
16094        let new_selections = old_selections
16095            .iter()
16096            .map(|selection| {
16097                let old_range = selection.start..selection.end;
16098
16099                let old_range =
16100                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16101                let excerpt = buffer.excerpt_containing(old_range.clone());
16102
16103                if let Some(mut excerpt) = excerpt
16104                    && let Some(node) = excerpt
16105                        .buffer()
16106                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16107                {
16108                    let new_range = excerpt.map_range_from_buffer(
16109                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16110                    );
16111                    selected_sibling = true;
16112                    Selection {
16113                        id: selection.id,
16114                        start: new_range.start,
16115                        end: new_range.end,
16116                        goal: SelectionGoal::None,
16117                        reversed: selection.reversed,
16118                    }
16119                } else {
16120                    selection.clone()
16121                }
16122            })
16123            .collect::<Vec<_>>();
16124
16125        if selected_sibling {
16126            self.change_selections(
16127                SelectionEffects::scroll(Autoscroll::fit()),
16128                window,
16129                cx,
16130                |s| {
16131                    s.select(new_selections);
16132                },
16133            );
16134        }
16135    }
16136
16137    pub fn select_prev_syntax_node(
16138        &mut self,
16139        _: &SelectPreviousSyntaxNode,
16140        window: &mut Window,
16141        cx: &mut Context<Self>,
16142    ) {
16143        let old_selections: Box<[_]> = self
16144            .selections
16145            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16146            .into();
16147        if old_selections.is_empty() {
16148            return;
16149        }
16150
16151        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16152
16153        let buffer = self.buffer.read(cx).snapshot(cx);
16154        let mut selected_sibling = false;
16155
16156        let new_selections = old_selections
16157            .iter()
16158            .map(|selection| {
16159                let old_range = selection.start..selection.end;
16160                let old_range =
16161                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16162                let excerpt = buffer.excerpt_containing(old_range.clone());
16163
16164                if let Some(mut excerpt) = excerpt
16165                    && let Some(node) = excerpt
16166                        .buffer()
16167                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16168                {
16169                    let new_range = excerpt.map_range_from_buffer(
16170                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16171                    );
16172                    selected_sibling = true;
16173                    Selection {
16174                        id: selection.id,
16175                        start: new_range.start,
16176                        end: new_range.end,
16177                        goal: SelectionGoal::None,
16178                        reversed: selection.reversed,
16179                    }
16180                } else {
16181                    selection.clone()
16182                }
16183            })
16184            .collect::<Vec<_>>();
16185
16186        if selected_sibling {
16187            self.change_selections(
16188                SelectionEffects::scroll(Autoscroll::fit()),
16189                window,
16190                cx,
16191                |s| {
16192                    s.select(new_selections);
16193                },
16194            );
16195        }
16196    }
16197
16198    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16199        if !EditorSettings::get_global(cx).gutter.runnables {
16200            self.clear_tasks();
16201            return Task::ready(());
16202        }
16203        let project = self.project().map(Entity::downgrade);
16204        let task_sources = self.lsp_task_sources(cx);
16205        let multi_buffer = self.buffer.downgrade();
16206        cx.spawn_in(window, async move |editor, cx| {
16207            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16208            let Some(project) = project.and_then(|p| p.upgrade()) else {
16209                return;
16210            };
16211            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16212                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16213            }) else {
16214                return;
16215            };
16216
16217            let hide_runnables = project
16218                .update(cx, |project, _| project.is_via_collab())
16219                .unwrap_or(true);
16220            if hide_runnables {
16221                return;
16222            }
16223            let new_rows =
16224                cx.background_spawn({
16225                    let snapshot = display_snapshot.clone();
16226                    async move {
16227                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16228                    }
16229                })
16230                    .await;
16231            let Ok(lsp_tasks) =
16232                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16233            else {
16234                return;
16235            };
16236            let lsp_tasks = lsp_tasks.await;
16237
16238            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16239                lsp_tasks
16240                    .into_iter()
16241                    .flat_map(|(kind, tasks)| {
16242                        tasks.into_iter().filter_map(move |(location, task)| {
16243                            Some((kind.clone(), location?, task))
16244                        })
16245                    })
16246                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16247                        let buffer = location.target.buffer;
16248                        let buffer_snapshot = buffer.read(cx).snapshot();
16249                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16250                            |(excerpt_id, snapshot, _)| {
16251                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16252                                    display_snapshot
16253                                        .buffer_snapshot()
16254                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16255                                } else {
16256                                    None
16257                                }
16258                            },
16259                        );
16260                        if let Some(offset) = offset {
16261                            let task_buffer_range =
16262                                location.target.range.to_point(&buffer_snapshot);
16263                            let context_buffer_range =
16264                                task_buffer_range.to_offset(&buffer_snapshot);
16265                            let context_range = BufferOffset(context_buffer_range.start)
16266                                ..BufferOffset(context_buffer_range.end);
16267
16268                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16269                                .or_insert_with(|| RunnableTasks {
16270                                    templates: Vec::new(),
16271                                    offset,
16272                                    column: task_buffer_range.start.column,
16273                                    extra_variables: HashMap::default(),
16274                                    context_range,
16275                                })
16276                                .templates
16277                                .push((kind, task.original_task().clone()));
16278                        }
16279
16280                        acc
16281                    })
16282            }) else {
16283                return;
16284            };
16285
16286            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16287                buffer.language_settings(cx).tasks.prefer_lsp
16288            }) else {
16289                return;
16290            };
16291
16292            let rows = Self::runnable_rows(
16293                project,
16294                display_snapshot,
16295                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16296                new_rows,
16297                cx.clone(),
16298            )
16299            .await;
16300            editor
16301                .update(cx, |editor, _| {
16302                    editor.clear_tasks();
16303                    for (key, mut value) in rows {
16304                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16305                            value.templates.extend(lsp_tasks.templates);
16306                        }
16307
16308                        editor.insert_tasks(key, value);
16309                    }
16310                    for (key, value) in lsp_tasks_by_rows {
16311                        editor.insert_tasks(key, value);
16312                    }
16313                })
16314                .ok();
16315        })
16316    }
16317    fn fetch_runnable_ranges(
16318        snapshot: &DisplaySnapshot,
16319        range: Range<Anchor>,
16320    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16321        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16322    }
16323
16324    fn runnable_rows(
16325        project: Entity<Project>,
16326        snapshot: DisplaySnapshot,
16327        prefer_lsp: bool,
16328        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16329        cx: AsyncWindowContext,
16330    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16331        cx.spawn(async move |cx| {
16332            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16333            for (run_range, mut runnable) in runnable_ranges {
16334                let Some(tasks) = cx
16335                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16336                    .ok()
16337                else {
16338                    continue;
16339                };
16340                let mut tasks = tasks.await;
16341
16342                if prefer_lsp {
16343                    tasks.retain(|(task_kind, _)| {
16344                        !matches!(task_kind, TaskSourceKind::Language { .. })
16345                    });
16346                }
16347                if tasks.is_empty() {
16348                    continue;
16349                }
16350
16351                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16352                let Some(row) = snapshot
16353                    .buffer_snapshot()
16354                    .buffer_line_for_row(MultiBufferRow(point.row))
16355                    .map(|(_, range)| range.start.row)
16356                else {
16357                    continue;
16358                };
16359
16360                let context_range =
16361                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16362                runnable_rows.push((
16363                    (runnable.buffer_id, row),
16364                    RunnableTasks {
16365                        templates: tasks,
16366                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16367                        context_range,
16368                        column: point.column,
16369                        extra_variables: runnable.extra_captures,
16370                    },
16371                ));
16372            }
16373            runnable_rows
16374        })
16375    }
16376
16377    fn templates_with_tags(
16378        project: &Entity<Project>,
16379        runnable: &mut Runnable,
16380        cx: &mut App,
16381    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16382        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16383            let (worktree_id, file) = project
16384                .buffer_for_id(runnable.buffer, cx)
16385                .and_then(|buffer| buffer.read(cx).file())
16386                .map(|file| (file.worktree_id(cx), file.clone()))
16387                .unzip();
16388
16389            (
16390                project.task_store().read(cx).task_inventory().cloned(),
16391                worktree_id,
16392                file,
16393            )
16394        });
16395
16396        let tags = mem::take(&mut runnable.tags);
16397        let language = runnable.language.clone();
16398        cx.spawn(async move |cx| {
16399            let mut templates_with_tags = Vec::new();
16400            if let Some(inventory) = inventory {
16401                for RunnableTag(tag) in tags {
16402                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16403                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16404                    }) else {
16405                        return templates_with_tags;
16406                    };
16407                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16408                        move |(_, template)| {
16409                            template.tags.iter().any(|source_tag| source_tag == &tag)
16410                        },
16411                    ));
16412                }
16413            }
16414            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16415
16416            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16417                // Strongest source wins; if we have worktree tag binding, prefer that to
16418                // global and language bindings;
16419                // if we have a global binding, prefer that to language binding.
16420                let first_mismatch = templates_with_tags
16421                    .iter()
16422                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16423                if let Some(index) = first_mismatch {
16424                    templates_with_tags.truncate(index);
16425                }
16426            }
16427
16428            templates_with_tags
16429        })
16430    }
16431
16432    pub fn move_to_enclosing_bracket(
16433        &mut self,
16434        _: &MoveToEnclosingBracket,
16435        window: &mut Window,
16436        cx: &mut Context<Self>,
16437    ) {
16438        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16439        self.change_selections(Default::default(), window, cx, |s| {
16440            s.move_offsets_with(|snapshot, selection| {
16441                let Some(enclosing_bracket_ranges) =
16442                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16443                else {
16444                    return;
16445                };
16446
16447                let mut best_length = usize::MAX;
16448                let mut best_inside = false;
16449                let mut best_in_bracket_range = false;
16450                let mut best_destination = None;
16451                for (open, close) in enclosing_bracket_ranges {
16452                    let close = close.to_inclusive();
16453                    let length = *close.end() - open.start;
16454                    let inside = selection.start >= open.end && selection.end <= *close.start();
16455                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16456                        || close.contains(&selection.head());
16457
16458                    // If best is next to a bracket and current isn't, skip
16459                    if !in_bracket_range && best_in_bracket_range {
16460                        continue;
16461                    }
16462
16463                    // Prefer smaller lengths unless best is inside and current isn't
16464                    if length > best_length && (best_inside || !inside) {
16465                        continue;
16466                    }
16467
16468                    best_length = length;
16469                    best_inside = inside;
16470                    best_in_bracket_range = in_bracket_range;
16471                    best_destination = Some(
16472                        if close.contains(&selection.start) && close.contains(&selection.end) {
16473                            if inside { open.end } else { open.start }
16474                        } else if inside {
16475                            *close.start()
16476                        } else {
16477                            *close.end()
16478                        },
16479                    );
16480                }
16481
16482                if let Some(destination) = best_destination {
16483                    selection.collapse_to(destination, SelectionGoal::None);
16484                }
16485            })
16486        });
16487    }
16488
16489    pub fn undo_selection(
16490        &mut self,
16491        _: &UndoSelection,
16492        window: &mut Window,
16493        cx: &mut Context<Self>,
16494    ) {
16495        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16496        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16497            self.selection_history.mode = SelectionHistoryMode::Undoing;
16498            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16499                this.end_selection(window, cx);
16500                this.change_selections(
16501                    SelectionEffects::scroll(Autoscroll::newest()),
16502                    window,
16503                    cx,
16504                    |s| s.select_anchors(entry.selections.to_vec()),
16505                );
16506            });
16507            self.selection_history.mode = SelectionHistoryMode::Normal;
16508
16509            self.select_next_state = entry.select_next_state;
16510            self.select_prev_state = entry.select_prev_state;
16511            self.add_selections_state = entry.add_selections_state;
16512        }
16513    }
16514
16515    pub fn redo_selection(
16516        &mut self,
16517        _: &RedoSelection,
16518        window: &mut Window,
16519        cx: &mut Context<Self>,
16520    ) {
16521        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16522        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16523            self.selection_history.mode = SelectionHistoryMode::Redoing;
16524            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16525                this.end_selection(window, cx);
16526                this.change_selections(
16527                    SelectionEffects::scroll(Autoscroll::newest()),
16528                    window,
16529                    cx,
16530                    |s| s.select_anchors(entry.selections.to_vec()),
16531                );
16532            });
16533            self.selection_history.mode = SelectionHistoryMode::Normal;
16534
16535            self.select_next_state = entry.select_next_state;
16536            self.select_prev_state = entry.select_prev_state;
16537            self.add_selections_state = entry.add_selections_state;
16538        }
16539    }
16540
16541    pub fn expand_excerpts(
16542        &mut self,
16543        action: &ExpandExcerpts,
16544        _: &mut Window,
16545        cx: &mut Context<Self>,
16546    ) {
16547        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16548    }
16549
16550    pub fn expand_excerpts_down(
16551        &mut self,
16552        action: &ExpandExcerptsDown,
16553        _: &mut Window,
16554        cx: &mut Context<Self>,
16555    ) {
16556        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16557    }
16558
16559    pub fn expand_excerpts_up(
16560        &mut self,
16561        action: &ExpandExcerptsUp,
16562        _: &mut Window,
16563        cx: &mut Context<Self>,
16564    ) {
16565        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16566    }
16567
16568    pub fn expand_excerpts_for_direction(
16569        &mut self,
16570        lines: u32,
16571        direction: ExpandExcerptDirection,
16572
16573        cx: &mut Context<Self>,
16574    ) {
16575        let selections = self.selections.disjoint_anchors_arc();
16576
16577        let lines = if lines == 0 {
16578            EditorSettings::get_global(cx).expand_excerpt_lines
16579        } else {
16580            lines
16581        };
16582
16583        self.buffer.update(cx, |buffer, cx| {
16584            let snapshot = buffer.snapshot(cx);
16585            let mut excerpt_ids = selections
16586                .iter()
16587                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16588                .collect::<Vec<_>>();
16589            excerpt_ids.sort();
16590            excerpt_ids.dedup();
16591            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16592        })
16593    }
16594
16595    pub fn expand_excerpt(
16596        &mut self,
16597        excerpt: ExcerptId,
16598        direction: ExpandExcerptDirection,
16599        window: &mut Window,
16600        cx: &mut Context<Self>,
16601    ) {
16602        let current_scroll_position = self.scroll_position(cx);
16603        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16604        let mut scroll = None;
16605
16606        if direction == ExpandExcerptDirection::Down {
16607            let multi_buffer = self.buffer.read(cx);
16608            let snapshot = multi_buffer.snapshot(cx);
16609            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16610                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16611                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16612            {
16613                let buffer_snapshot = buffer.read(cx).snapshot();
16614                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16615                let last_row = buffer_snapshot.max_point().row;
16616                let lines_below = last_row.saturating_sub(excerpt_end_row);
16617                if lines_below >= lines_to_expand {
16618                    scroll = Some(
16619                        current_scroll_position
16620                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16621                    );
16622                }
16623            }
16624        }
16625        if direction == ExpandExcerptDirection::Up
16626            && self
16627                .buffer
16628                .read(cx)
16629                .snapshot(cx)
16630                .excerpt_before(excerpt)
16631                .is_none()
16632        {
16633            scroll = Some(current_scroll_position);
16634        }
16635
16636        self.buffer.update(cx, |buffer, cx| {
16637            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16638        });
16639
16640        if let Some(new_scroll_position) = scroll {
16641            self.set_scroll_position(new_scroll_position, window, cx);
16642        }
16643    }
16644
16645    pub fn go_to_singleton_buffer_point(
16646        &mut self,
16647        point: Point,
16648        window: &mut Window,
16649        cx: &mut Context<Self>,
16650    ) {
16651        self.go_to_singleton_buffer_range(point..point, window, cx);
16652    }
16653
16654    pub fn go_to_singleton_buffer_range(
16655        &mut self,
16656        range: Range<Point>,
16657        window: &mut Window,
16658        cx: &mut Context<Self>,
16659    ) {
16660        let multibuffer = self.buffer().read(cx);
16661        let Some(buffer) = multibuffer.as_singleton() else {
16662            return;
16663        };
16664        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16665            return;
16666        };
16667        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16668            return;
16669        };
16670        self.change_selections(
16671            SelectionEffects::default().nav_history(true),
16672            window,
16673            cx,
16674            |s| s.select_anchor_ranges([start..end]),
16675        );
16676    }
16677
16678    pub fn go_to_diagnostic(
16679        &mut self,
16680        action: &GoToDiagnostic,
16681        window: &mut Window,
16682        cx: &mut Context<Self>,
16683    ) {
16684        if !self.diagnostics_enabled() {
16685            return;
16686        }
16687        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16688        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16689    }
16690
16691    pub fn go_to_prev_diagnostic(
16692        &mut self,
16693        action: &GoToPreviousDiagnostic,
16694        window: &mut Window,
16695        cx: &mut Context<Self>,
16696    ) {
16697        if !self.diagnostics_enabled() {
16698            return;
16699        }
16700        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16701        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16702    }
16703
16704    pub fn go_to_diagnostic_impl(
16705        &mut self,
16706        direction: Direction,
16707        severity: GoToDiagnosticSeverityFilter,
16708        window: &mut Window,
16709        cx: &mut Context<Self>,
16710    ) {
16711        let buffer = self.buffer.read(cx).snapshot(cx);
16712        let selection = self
16713            .selections
16714            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16715
16716        let mut active_group_id = None;
16717        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16718            && active_group.active_range.start.to_offset(&buffer) == selection.start
16719        {
16720            active_group_id = Some(active_group.group_id);
16721        }
16722
16723        fn filtered<'a>(
16724            severity: GoToDiagnosticSeverityFilter,
16725            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16726        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16727            diagnostics
16728                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16729                .filter(|entry| entry.range.start != entry.range.end)
16730                .filter(|entry| !entry.diagnostic.is_unnecessary)
16731        }
16732
16733        let before = filtered(
16734            severity,
16735            buffer
16736                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16737                .filter(|entry| entry.range.start <= selection.start),
16738        );
16739        let after = filtered(
16740            severity,
16741            buffer
16742                .diagnostics_in_range(selection.start..buffer.len())
16743                .filter(|entry| entry.range.start >= selection.start),
16744        );
16745
16746        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16747        if direction == Direction::Prev {
16748            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16749            {
16750                for diagnostic in prev_diagnostics.into_iter().rev() {
16751                    if diagnostic.range.start != selection.start
16752                        || active_group_id
16753                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16754                    {
16755                        found = Some(diagnostic);
16756                        break 'outer;
16757                    }
16758                }
16759            }
16760        } else {
16761            for diagnostic in after.chain(before) {
16762                if diagnostic.range.start != selection.start
16763                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16764                {
16765                    found = Some(diagnostic);
16766                    break;
16767                }
16768            }
16769        }
16770        let Some(next_diagnostic) = found else {
16771            return;
16772        };
16773
16774        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16775        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16776            return;
16777        };
16778        let snapshot = self.snapshot(window, cx);
16779        if snapshot.intersects_fold(next_diagnostic.range.start) {
16780            self.unfold_ranges(
16781                std::slice::from_ref(&next_diagnostic.range),
16782                true,
16783                false,
16784                cx,
16785            );
16786        }
16787        self.change_selections(Default::default(), window, cx, |s| {
16788            s.select_ranges(vec![
16789                next_diagnostic.range.start..next_diagnostic.range.start,
16790            ])
16791        });
16792        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16793        self.refresh_edit_prediction(false, true, window, cx);
16794    }
16795
16796    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16797        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16798        let snapshot = self.snapshot(window, cx);
16799        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16800        self.go_to_hunk_before_or_after_position(
16801            &snapshot,
16802            selection.head(),
16803            Direction::Next,
16804            window,
16805            cx,
16806        );
16807    }
16808
16809    pub fn go_to_hunk_before_or_after_position(
16810        &mut self,
16811        snapshot: &EditorSnapshot,
16812        position: Point,
16813        direction: Direction,
16814        window: &mut Window,
16815        cx: &mut Context<Editor>,
16816    ) {
16817        let row = if direction == Direction::Next {
16818            self.hunk_after_position(snapshot, position)
16819                .map(|hunk| hunk.row_range.start)
16820        } else {
16821            self.hunk_before_position(snapshot, position)
16822        };
16823
16824        if let Some(row) = row {
16825            let destination = Point::new(row.0, 0);
16826            let autoscroll = Autoscroll::center();
16827
16828            self.unfold_ranges(&[destination..destination], false, false, cx);
16829            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16830                s.select_ranges([destination..destination]);
16831            });
16832        }
16833    }
16834
16835    fn hunk_after_position(
16836        &mut self,
16837        snapshot: &EditorSnapshot,
16838        position: Point,
16839    ) -> Option<MultiBufferDiffHunk> {
16840        snapshot
16841            .buffer_snapshot()
16842            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16843            .find(|hunk| hunk.row_range.start.0 > position.row)
16844            .or_else(|| {
16845                snapshot
16846                    .buffer_snapshot()
16847                    .diff_hunks_in_range(Point::zero()..position)
16848                    .find(|hunk| hunk.row_range.end.0 < position.row)
16849            })
16850    }
16851
16852    fn go_to_prev_hunk(
16853        &mut self,
16854        _: &GoToPreviousHunk,
16855        window: &mut Window,
16856        cx: &mut Context<Self>,
16857    ) {
16858        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16859        let snapshot = self.snapshot(window, cx);
16860        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16861        self.go_to_hunk_before_or_after_position(
16862            &snapshot,
16863            selection.head(),
16864            Direction::Prev,
16865            window,
16866            cx,
16867        );
16868    }
16869
16870    fn hunk_before_position(
16871        &mut self,
16872        snapshot: &EditorSnapshot,
16873        position: Point,
16874    ) -> Option<MultiBufferRow> {
16875        snapshot
16876            .buffer_snapshot()
16877            .diff_hunk_before(position)
16878            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16879    }
16880
16881    fn go_to_next_change(
16882        &mut self,
16883        _: &GoToNextChange,
16884        window: &mut Window,
16885        cx: &mut Context<Self>,
16886    ) {
16887        if let Some(selections) = self
16888            .change_list
16889            .next_change(1, Direction::Next)
16890            .map(|s| s.to_vec())
16891        {
16892            self.change_selections(Default::default(), window, cx, |s| {
16893                let map = s.display_snapshot();
16894                s.select_display_ranges(selections.iter().map(|a| {
16895                    let point = a.to_display_point(&map);
16896                    point..point
16897                }))
16898            })
16899        }
16900    }
16901
16902    fn go_to_previous_change(
16903        &mut self,
16904        _: &GoToPreviousChange,
16905        window: &mut Window,
16906        cx: &mut Context<Self>,
16907    ) {
16908        if let Some(selections) = self
16909            .change_list
16910            .next_change(1, Direction::Prev)
16911            .map(|s| s.to_vec())
16912        {
16913            self.change_selections(Default::default(), window, cx, |s| {
16914                let map = s.display_snapshot();
16915                s.select_display_ranges(selections.iter().map(|a| {
16916                    let point = a.to_display_point(&map);
16917                    point..point
16918                }))
16919            })
16920        }
16921    }
16922
16923    pub fn go_to_next_document_highlight(
16924        &mut self,
16925        _: &GoToNextDocumentHighlight,
16926        window: &mut Window,
16927        cx: &mut Context<Self>,
16928    ) {
16929        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16930    }
16931
16932    pub fn go_to_prev_document_highlight(
16933        &mut self,
16934        _: &GoToPreviousDocumentHighlight,
16935        window: &mut Window,
16936        cx: &mut Context<Self>,
16937    ) {
16938        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16939    }
16940
16941    pub fn go_to_document_highlight_before_or_after_position(
16942        &mut self,
16943        direction: Direction,
16944        window: &mut Window,
16945        cx: &mut Context<Editor>,
16946    ) {
16947        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16948        let snapshot = self.snapshot(window, cx);
16949        let buffer = &snapshot.buffer_snapshot();
16950        let position = self
16951            .selections
16952            .newest::<Point>(&snapshot.display_snapshot)
16953            .head();
16954        let anchor_position = buffer.anchor_after(position);
16955
16956        // Get all document highlights (both read and write)
16957        let mut all_highlights = Vec::new();
16958
16959        if let Some((_, read_highlights)) = self
16960            .background_highlights
16961            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16962        {
16963            all_highlights.extend(read_highlights.iter());
16964        }
16965
16966        if let Some((_, write_highlights)) = self
16967            .background_highlights
16968            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16969        {
16970            all_highlights.extend(write_highlights.iter());
16971        }
16972
16973        if all_highlights.is_empty() {
16974            return;
16975        }
16976
16977        // Sort highlights by position
16978        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16979
16980        let target_highlight = match direction {
16981            Direction::Next => {
16982                // Find the first highlight after the current position
16983                all_highlights
16984                    .iter()
16985                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16986            }
16987            Direction::Prev => {
16988                // Find the last highlight before the current position
16989                all_highlights
16990                    .iter()
16991                    .rev()
16992                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16993            }
16994        };
16995
16996        if let Some(highlight) = target_highlight {
16997            let destination = highlight.start.to_point(buffer);
16998            let autoscroll = Autoscroll::center();
16999
17000            self.unfold_ranges(&[destination..destination], false, false, cx);
17001            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17002                s.select_ranges([destination..destination]);
17003            });
17004        }
17005    }
17006
17007    fn go_to_line<T: 'static>(
17008        &mut self,
17009        position: Anchor,
17010        highlight_color: Option<Hsla>,
17011        window: &mut Window,
17012        cx: &mut Context<Self>,
17013    ) {
17014        let snapshot = self.snapshot(window, cx).display_snapshot;
17015        let position = position.to_point(&snapshot.buffer_snapshot());
17016        let start = snapshot
17017            .buffer_snapshot()
17018            .clip_point(Point::new(position.row, 0), Bias::Left);
17019        let end = start + Point::new(1, 0);
17020        let start = snapshot.buffer_snapshot().anchor_before(start);
17021        let end = snapshot.buffer_snapshot().anchor_before(end);
17022
17023        self.highlight_rows::<T>(
17024            start..end,
17025            highlight_color
17026                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17027            Default::default(),
17028            cx,
17029        );
17030
17031        if self.buffer.read(cx).is_singleton() {
17032            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17033        }
17034    }
17035
17036    pub fn go_to_definition(
17037        &mut self,
17038        _: &GoToDefinition,
17039        window: &mut Window,
17040        cx: &mut Context<Self>,
17041    ) -> Task<Result<Navigated>> {
17042        let definition =
17043            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17044        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17045        cx.spawn_in(window, async move |editor, cx| {
17046            if definition.await? == Navigated::Yes {
17047                return Ok(Navigated::Yes);
17048            }
17049            match fallback_strategy {
17050                GoToDefinitionFallback::None => Ok(Navigated::No),
17051                GoToDefinitionFallback::FindAllReferences => {
17052                    match editor.update_in(cx, |editor, window, cx| {
17053                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17054                    })? {
17055                        Some(references) => references.await,
17056                        None => Ok(Navigated::No),
17057                    }
17058                }
17059            }
17060        })
17061    }
17062
17063    pub fn go_to_declaration(
17064        &mut self,
17065        _: &GoToDeclaration,
17066        window: &mut Window,
17067        cx: &mut Context<Self>,
17068    ) -> Task<Result<Navigated>> {
17069        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17070    }
17071
17072    pub fn go_to_declaration_split(
17073        &mut self,
17074        _: &GoToDeclaration,
17075        window: &mut Window,
17076        cx: &mut Context<Self>,
17077    ) -> Task<Result<Navigated>> {
17078        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17079    }
17080
17081    pub fn go_to_implementation(
17082        &mut self,
17083        _: &GoToImplementation,
17084        window: &mut Window,
17085        cx: &mut Context<Self>,
17086    ) -> Task<Result<Navigated>> {
17087        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17088    }
17089
17090    pub fn go_to_implementation_split(
17091        &mut self,
17092        _: &GoToImplementationSplit,
17093        window: &mut Window,
17094        cx: &mut Context<Self>,
17095    ) -> Task<Result<Navigated>> {
17096        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17097    }
17098
17099    pub fn go_to_type_definition(
17100        &mut self,
17101        _: &GoToTypeDefinition,
17102        window: &mut Window,
17103        cx: &mut Context<Self>,
17104    ) -> Task<Result<Navigated>> {
17105        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17106    }
17107
17108    pub fn go_to_definition_split(
17109        &mut self,
17110        _: &GoToDefinitionSplit,
17111        window: &mut Window,
17112        cx: &mut Context<Self>,
17113    ) -> Task<Result<Navigated>> {
17114        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17115    }
17116
17117    pub fn go_to_type_definition_split(
17118        &mut self,
17119        _: &GoToTypeDefinitionSplit,
17120        window: &mut Window,
17121        cx: &mut Context<Self>,
17122    ) -> Task<Result<Navigated>> {
17123        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17124    }
17125
17126    fn go_to_definition_of_kind(
17127        &mut self,
17128        kind: GotoDefinitionKind,
17129        split: bool,
17130        window: &mut Window,
17131        cx: &mut Context<Self>,
17132    ) -> Task<Result<Navigated>> {
17133        let Some(provider) = self.semantics_provider.clone() else {
17134            return Task::ready(Ok(Navigated::No));
17135        };
17136        let head = self
17137            .selections
17138            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17139            .head();
17140        let buffer = self.buffer.read(cx);
17141        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17142            return Task::ready(Ok(Navigated::No));
17143        };
17144        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17145            return Task::ready(Ok(Navigated::No));
17146        };
17147
17148        cx.spawn_in(window, async move |editor, cx| {
17149            let Some(definitions) = definitions.await? else {
17150                return Ok(Navigated::No);
17151            };
17152            let navigated = editor
17153                .update_in(cx, |editor, window, cx| {
17154                    editor.navigate_to_hover_links(
17155                        Some(kind),
17156                        definitions
17157                            .into_iter()
17158                            .filter(|location| {
17159                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17160                            })
17161                            .map(HoverLink::Text)
17162                            .collect::<Vec<_>>(),
17163                        split,
17164                        window,
17165                        cx,
17166                    )
17167                })?
17168                .await?;
17169            anyhow::Ok(navigated)
17170        })
17171    }
17172
17173    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17174        let selection = self.selections.newest_anchor();
17175        let head = selection.head();
17176        let tail = selection.tail();
17177
17178        let Some((buffer, start_position)) =
17179            self.buffer.read(cx).text_anchor_for_position(head, cx)
17180        else {
17181            return;
17182        };
17183
17184        let end_position = if head != tail {
17185            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17186                return;
17187            };
17188            Some(pos)
17189        } else {
17190            None
17191        };
17192
17193        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17194            let url = if let Some(end_pos) = end_position {
17195                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17196            } else {
17197                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17198            };
17199
17200            if let Some(url) = url {
17201                cx.update(|window, cx| {
17202                    if parse_zed_link(&url, cx).is_some() {
17203                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17204                    } else {
17205                        cx.open_url(&url);
17206                    }
17207                })?;
17208            }
17209
17210            anyhow::Ok(())
17211        });
17212
17213        url_finder.detach();
17214    }
17215
17216    pub fn open_selected_filename(
17217        &mut self,
17218        _: &OpenSelectedFilename,
17219        window: &mut Window,
17220        cx: &mut Context<Self>,
17221    ) {
17222        let Some(workspace) = self.workspace() else {
17223            return;
17224        };
17225
17226        let position = self.selections.newest_anchor().head();
17227
17228        let Some((buffer, buffer_position)) =
17229            self.buffer.read(cx).text_anchor_for_position(position, cx)
17230        else {
17231            return;
17232        };
17233
17234        let project = self.project.clone();
17235
17236        cx.spawn_in(window, async move |_, cx| {
17237            let result = find_file(&buffer, project, buffer_position, cx).await;
17238
17239            if let Some((_, path)) = result {
17240                workspace
17241                    .update_in(cx, |workspace, window, cx| {
17242                        workspace.open_resolved_path(path, window, cx)
17243                    })?
17244                    .await?;
17245            }
17246            anyhow::Ok(())
17247        })
17248        .detach();
17249    }
17250
17251    pub(crate) fn navigate_to_hover_links(
17252        &mut self,
17253        kind: Option<GotoDefinitionKind>,
17254        definitions: Vec<HoverLink>,
17255        split: bool,
17256        window: &mut Window,
17257        cx: &mut Context<Editor>,
17258    ) -> Task<Result<Navigated>> {
17259        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17260        let mut first_url_or_file = None;
17261        let definitions: Vec<_> = definitions
17262            .into_iter()
17263            .filter_map(|def| match def {
17264                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17265                HoverLink::InlayHint(lsp_location, server_id) => {
17266                    let computation =
17267                        self.compute_target_location(lsp_location, server_id, window, cx);
17268                    Some(cx.background_spawn(computation))
17269                }
17270                HoverLink::Url(url) => {
17271                    first_url_or_file = Some(Either::Left(url));
17272                    None
17273                }
17274                HoverLink::File(path) => {
17275                    first_url_or_file = Some(Either::Right(path));
17276                    None
17277                }
17278            })
17279            .collect();
17280
17281        let workspace = self.workspace();
17282
17283        cx.spawn_in(window, async move |editor, cx| {
17284            let locations: Vec<Location> = future::join_all(definitions)
17285                .await
17286                .into_iter()
17287                .filter_map(|location| location.transpose())
17288                .collect::<Result<_>>()
17289                .context("location tasks")?;
17290            let mut locations = cx.update(|_, cx| {
17291                locations
17292                    .into_iter()
17293                    .map(|location| {
17294                        let buffer = location.buffer.read(cx);
17295                        (location.buffer, location.range.to_point(buffer))
17296                    })
17297                    .into_group_map()
17298            })?;
17299            let mut num_locations = 0;
17300            for ranges in locations.values_mut() {
17301                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17302                ranges.dedup();
17303                num_locations += ranges.len();
17304            }
17305
17306            if num_locations > 1 {
17307                let tab_kind = match kind {
17308                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17309                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17310                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17311                    Some(GotoDefinitionKind::Type) => "Types",
17312                };
17313                let title = editor
17314                    .update_in(cx, |_, _, cx| {
17315                        let target = locations
17316                            .iter()
17317                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17318                            .map(|(buffer, location)| {
17319                                buffer
17320                                    .read(cx)
17321                                    .text_for_range(location.clone())
17322                                    .collect::<String>()
17323                            })
17324                            .filter(|text| !text.contains('\n'))
17325                            .unique()
17326                            .take(3)
17327                            .join(", ");
17328                        if target.is_empty() {
17329                            tab_kind.to_owned()
17330                        } else {
17331                            format!("{tab_kind} for {target}")
17332                        }
17333                    })
17334                    .context("buffer title")?;
17335
17336                let Some(workspace) = workspace else {
17337                    return Ok(Navigated::No);
17338                };
17339
17340                let opened = workspace
17341                    .update_in(cx, |workspace, window, cx| {
17342                        let allow_preview = PreviewTabsSettings::get_global(cx)
17343                            .enable_preview_multibuffer_from_code_navigation;
17344                        Self::open_locations_in_multibuffer(
17345                            workspace,
17346                            locations,
17347                            title,
17348                            split,
17349                            allow_preview,
17350                            MultibufferSelectionMode::First,
17351                            window,
17352                            cx,
17353                        )
17354                    })
17355                    .is_ok();
17356
17357                anyhow::Ok(Navigated::from_bool(opened))
17358            } else if num_locations == 0 {
17359                // If there is one url or file, open it directly
17360                match first_url_or_file {
17361                    Some(Either::Left(url)) => {
17362                        cx.update(|window, cx| {
17363                            if parse_zed_link(&url, cx).is_some() {
17364                                window
17365                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17366                            } else {
17367                                cx.open_url(&url);
17368                            }
17369                        })?;
17370                        Ok(Navigated::Yes)
17371                    }
17372                    Some(Either::Right(path)) => {
17373                        // TODO(andrew): respect preview tab settings
17374                        //               `enable_keep_preview_on_code_navigation` and
17375                        //               `enable_preview_file_from_code_navigation`
17376                        let Some(workspace) = workspace else {
17377                            return Ok(Navigated::No);
17378                        };
17379                        workspace
17380                            .update_in(cx, |workspace, window, cx| {
17381                                workspace.open_resolved_path(path, window, cx)
17382                            })?
17383                            .await?;
17384                        Ok(Navigated::Yes)
17385                    }
17386                    None => Ok(Navigated::No),
17387                }
17388            } else {
17389                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17390                let target_range = target_ranges.first().unwrap().clone();
17391
17392                editor.update_in(cx, |editor, window, cx| {
17393                    let range = target_range.to_point(target_buffer.read(cx));
17394                    let range = editor.range_for_match(&range);
17395                    let range = collapse_multiline_range(range);
17396
17397                    if !split
17398                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17399                    {
17400                        editor.go_to_singleton_buffer_range(range, window, cx);
17401                    } else {
17402                        let Some(workspace) = workspace else {
17403                            return Navigated::No;
17404                        };
17405                        let pane = workspace.read(cx).active_pane().clone();
17406                        window.defer(cx, move |window, cx| {
17407                            let target_editor: Entity<Self> =
17408                                workspace.update(cx, |workspace, cx| {
17409                                    let pane = if split {
17410                                        workspace.adjacent_pane(window, cx)
17411                                    } else {
17412                                        workspace.active_pane().clone()
17413                                    };
17414
17415                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17416                                    let keep_old_preview = preview_tabs_settings
17417                                        .enable_keep_preview_on_code_navigation;
17418                                    let allow_new_preview = preview_tabs_settings
17419                                        .enable_preview_file_from_code_navigation;
17420
17421                                    workspace.open_project_item(
17422                                        pane,
17423                                        target_buffer.clone(),
17424                                        true,
17425                                        true,
17426                                        keep_old_preview,
17427                                        allow_new_preview,
17428                                        window,
17429                                        cx,
17430                                    )
17431                                });
17432                            target_editor.update(cx, |target_editor, cx| {
17433                                // When selecting a definition in a different buffer, disable the nav history
17434                                // to avoid creating a history entry at the previous cursor location.
17435                                pane.update(cx, |pane, _| pane.disable_history());
17436                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17437                                pane.update(cx, |pane, _| pane.enable_history());
17438                            });
17439                        });
17440                    }
17441                    Navigated::Yes
17442                })
17443            }
17444        })
17445    }
17446
17447    fn compute_target_location(
17448        &self,
17449        lsp_location: lsp::Location,
17450        server_id: LanguageServerId,
17451        window: &mut Window,
17452        cx: &mut Context<Self>,
17453    ) -> Task<anyhow::Result<Option<Location>>> {
17454        let Some(project) = self.project.clone() else {
17455            return Task::ready(Ok(None));
17456        };
17457
17458        cx.spawn_in(window, async move |editor, cx| {
17459            let location_task = editor.update(cx, |_, cx| {
17460                project.update(cx, |project, cx| {
17461                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17462                })
17463            })?;
17464            let location = Some({
17465                let target_buffer_handle = location_task.await.context("open local buffer")?;
17466                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17467                    let target_start = target_buffer
17468                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17469                    let target_end = target_buffer
17470                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17471                    target_buffer.anchor_after(target_start)
17472                        ..target_buffer.anchor_before(target_end)
17473                })?;
17474                Location {
17475                    buffer: target_buffer_handle,
17476                    range,
17477                }
17478            });
17479            Ok(location)
17480        })
17481    }
17482
17483    fn go_to_next_reference(
17484        &mut self,
17485        _: &GoToNextReference,
17486        window: &mut Window,
17487        cx: &mut Context<Self>,
17488    ) {
17489        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17490        if let Some(task) = task {
17491            task.detach();
17492        };
17493    }
17494
17495    fn go_to_prev_reference(
17496        &mut self,
17497        _: &GoToPreviousReference,
17498        window: &mut Window,
17499        cx: &mut Context<Self>,
17500    ) {
17501        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17502        if let Some(task) = task {
17503            task.detach();
17504        };
17505    }
17506
17507    pub fn go_to_reference_before_or_after_position(
17508        &mut self,
17509        direction: Direction,
17510        count: usize,
17511        window: &mut Window,
17512        cx: &mut Context<Self>,
17513    ) -> Option<Task<Result<()>>> {
17514        let selection = self.selections.newest_anchor();
17515        let head = selection.head();
17516
17517        let multi_buffer = self.buffer.read(cx);
17518
17519        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17520        let workspace = self.workspace()?;
17521        let project = workspace.read(cx).project().clone();
17522        let references =
17523            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17524        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17525            let Some(locations) = references.await? else {
17526                return Ok(());
17527            };
17528
17529            if locations.is_empty() {
17530                // totally normal - the cursor may be on something which is not
17531                // a symbol (e.g. a keyword)
17532                log::info!("no references found under cursor");
17533                return Ok(());
17534            }
17535
17536            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17537
17538            let (locations, current_location_index) =
17539                multi_buffer.update(cx, |multi_buffer, cx| {
17540                    let mut locations = locations
17541                        .into_iter()
17542                        .filter_map(|loc| {
17543                            let start = multi_buffer.buffer_anchor_to_anchor(
17544                                &loc.buffer,
17545                                loc.range.start,
17546                                cx,
17547                            )?;
17548                            let end = multi_buffer.buffer_anchor_to_anchor(
17549                                &loc.buffer,
17550                                loc.range.end,
17551                                cx,
17552                            )?;
17553                            Some(start..end)
17554                        })
17555                        .collect::<Vec<_>>();
17556
17557                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17558                    // There is an O(n) implementation, but given this list will be
17559                    // small (usually <100 items), the extra O(log(n)) factor isn't
17560                    // worth the (surprisingly large amount of) extra complexity.
17561                    locations
17562                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17563
17564                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17565
17566                    let current_location_index = locations.iter().position(|loc| {
17567                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17568                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17569                    });
17570
17571                    (locations, current_location_index)
17572                })?;
17573
17574            let Some(current_location_index) = current_location_index else {
17575                // This indicates something has gone wrong, because we already
17576                // handle the "no references" case above
17577                log::error!(
17578                    "failed to find current reference under cursor. Total references: {}",
17579                    locations.len()
17580                );
17581                return Ok(());
17582            };
17583
17584            let destination_location_index = match direction {
17585                Direction::Next => (current_location_index + count) % locations.len(),
17586                Direction::Prev => {
17587                    (current_location_index + locations.len() - count % locations.len())
17588                        % locations.len()
17589                }
17590            };
17591
17592            // TODO(cameron): is this needed?
17593            // the thinking is to avoid "jumping to the current location" (avoid
17594            // polluting "jumplist" in vim terms)
17595            if current_location_index == destination_location_index {
17596                return Ok(());
17597            }
17598
17599            let Range { start, end } = locations[destination_location_index];
17600
17601            editor.update_in(cx, |editor, window, cx| {
17602                let effects = SelectionEffects::default();
17603
17604                editor.unfold_ranges(&[start..end], false, false, cx);
17605                editor.change_selections(effects, window, cx, |s| {
17606                    s.select_ranges([start..start]);
17607                });
17608            })?;
17609
17610            Ok(())
17611        }))
17612    }
17613
17614    pub fn find_all_references(
17615        &mut self,
17616        action: &FindAllReferences,
17617        window: &mut Window,
17618        cx: &mut Context<Self>,
17619    ) -> Option<Task<Result<Navigated>>> {
17620        let always_open_multibuffer = action.always_open_multibuffer;
17621        let selection = self.selections.newest_anchor();
17622        let multi_buffer = self.buffer.read(cx);
17623        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17624        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
17625        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
17626        let head = selection_offset.head();
17627
17628        let head_anchor = multi_buffer_snapshot.anchor_at(
17629            head,
17630            if head < selection_offset.tail() {
17631                Bias::Right
17632            } else {
17633                Bias::Left
17634            },
17635        );
17636
17637        match self
17638            .find_all_references_task_sources
17639            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17640        {
17641            Ok(_) => {
17642                log::info!(
17643                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17644                );
17645                return None;
17646            }
17647            Err(i) => {
17648                self.find_all_references_task_sources.insert(i, head_anchor);
17649            }
17650        }
17651
17652        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17653        let workspace = self.workspace()?;
17654        let project = workspace.read(cx).project().clone();
17655        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17656        Some(cx.spawn_in(window, async move |editor, cx| {
17657            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17658                if let Ok(i) = editor
17659                    .find_all_references_task_sources
17660                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17661                {
17662                    editor.find_all_references_task_sources.remove(i);
17663                }
17664            });
17665
17666            let Some(locations) = references.await? else {
17667                return anyhow::Ok(Navigated::No);
17668            };
17669            let mut locations = cx.update(|_, cx| {
17670                locations
17671                    .into_iter()
17672                    .map(|location| {
17673                        let buffer = location.buffer.read(cx);
17674                        (location.buffer, location.range.to_point(buffer))
17675                    })
17676                    // if special-casing the single-match case, remove ranges
17677                    // that intersect current selection
17678                    .filter(|(location_buffer, location)| {
17679                        if always_open_multibuffer || &buffer != location_buffer {
17680                            return true;
17681                        }
17682
17683                        !location.contains_inclusive(&selection_point.range())
17684                    })
17685                    .into_group_map()
17686            })?;
17687            if locations.is_empty() {
17688                return anyhow::Ok(Navigated::No);
17689            }
17690            for ranges in locations.values_mut() {
17691                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17692                ranges.dedup();
17693            }
17694            let mut num_locations = 0;
17695            for ranges in locations.values_mut() {
17696                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17697                ranges.dedup();
17698                num_locations += ranges.len();
17699            }
17700
17701            if num_locations == 1 && !always_open_multibuffer {
17702                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17703                let target_range = target_ranges.first().unwrap().clone();
17704
17705                return editor.update_in(cx, |editor, window, cx| {
17706                    let range = target_range.to_point(target_buffer.read(cx));
17707                    let range = editor.range_for_match(&range);
17708                    let range = range.start..range.start;
17709
17710                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
17711                        editor.go_to_singleton_buffer_range(range, window, cx);
17712                    } else {
17713                        let pane = workspace.read(cx).active_pane().clone();
17714                        window.defer(cx, move |window, cx| {
17715                            let target_editor: Entity<Self> =
17716                                workspace.update(cx, |workspace, cx| {
17717                                    let pane = workspace.active_pane().clone();
17718
17719                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17720                                    let keep_old_preview = preview_tabs_settings
17721                                        .enable_keep_preview_on_code_navigation;
17722                                    let allow_new_preview = preview_tabs_settings
17723                                        .enable_preview_file_from_code_navigation;
17724
17725                                    workspace.open_project_item(
17726                                        pane,
17727                                        target_buffer.clone(),
17728                                        true,
17729                                        true,
17730                                        keep_old_preview,
17731                                        allow_new_preview,
17732                                        window,
17733                                        cx,
17734                                    )
17735                                });
17736                            target_editor.update(cx, |target_editor, cx| {
17737                                // When selecting a definition in a different buffer, disable the nav history
17738                                // to avoid creating a history entry at the previous cursor location.
17739                                pane.update(cx, |pane, _| pane.disable_history());
17740                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17741                                pane.update(cx, |pane, _| pane.enable_history());
17742                            });
17743                        });
17744                    }
17745                    Navigated::No
17746                });
17747            }
17748
17749            workspace.update_in(cx, |workspace, window, cx| {
17750                let target = locations
17751                    .iter()
17752                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17753                    .map(|(buffer, location)| {
17754                        buffer
17755                            .read(cx)
17756                            .text_for_range(location.clone())
17757                            .collect::<String>()
17758                    })
17759                    .filter(|text| !text.contains('\n'))
17760                    .unique()
17761                    .take(3)
17762                    .join(", ");
17763                let title = if target.is_empty() {
17764                    "References".to_owned()
17765                } else {
17766                    format!("References to {target}")
17767                };
17768                let allow_preview = PreviewTabsSettings::get_global(cx)
17769                    .enable_preview_multibuffer_from_code_navigation;
17770                Self::open_locations_in_multibuffer(
17771                    workspace,
17772                    locations,
17773                    title,
17774                    false,
17775                    allow_preview,
17776                    MultibufferSelectionMode::First,
17777                    window,
17778                    cx,
17779                );
17780                Navigated::Yes
17781            })
17782        }))
17783    }
17784
17785    /// Opens a multibuffer with the given project locations in it.
17786    pub fn open_locations_in_multibuffer(
17787        workspace: &mut Workspace,
17788        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17789        title: String,
17790        split: bool,
17791        allow_preview: bool,
17792        multibuffer_selection_mode: MultibufferSelectionMode,
17793        window: &mut Window,
17794        cx: &mut Context<Workspace>,
17795    ) {
17796        if locations.is_empty() {
17797            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17798            return;
17799        }
17800
17801        let capability = workspace.project().read(cx).capability();
17802        let mut ranges = <Vec<Range<Anchor>>>::new();
17803
17804        // a key to find existing multibuffer editors with the same set of locations
17805        // to prevent us from opening more and more multibuffer tabs for searches and the like
17806        let mut key = (title.clone(), vec![]);
17807        let excerpt_buffer = cx.new(|cx| {
17808            let key = &mut key.1;
17809            let mut multibuffer = MultiBuffer::new(capability);
17810            for (buffer, mut ranges_for_buffer) in locations {
17811                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17812                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17813                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17814                    PathKey::for_buffer(&buffer, cx),
17815                    buffer.clone(),
17816                    ranges_for_buffer,
17817                    multibuffer_context_lines(cx),
17818                    cx,
17819                );
17820                ranges.extend(new_ranges)
17821            }
17822
17823            multibuffer.with_title(title)
17824        });
17825        let existing = workspace.active_pane().update(cx, |pane, cx| {
17826            pane.items()
17827                .filter_map(|item| item.downcast::<Editor>())
17828                .find(|editor| {
17829                    editor
17830                        .read(cx)
17831                        .lookup_key
17832                        .as_ref()
17833                        .and_then(|it| {
17834                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17835                        })
17836                        .is_some_and(|it| *it == key)
17837                })
17838        });
17839        let was_existing = existing.is_some();
17840        let editor = existing.unwrap_or_else(|| {
17841            cx.new(|cx| {
17842                let mut editor = Editor::for_multibuffer(
17843                    excerpt_buffer,
17844                    Some(workspace.project().clone()),
17845                    window,
17846                    cx,
17847                );
17848                editor.lookup_key = Some(Box::new(key));
17849                editor
17850            })
17851        });
17852        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17853            MultibufferSelectionMode::First => {
17854                if let Some(first_range) = ranges.first() {
17855                    editor.change_selections(
17856                        SelectionEffects::no_scroll(),
17857                        window,
17858                        cx,
17859                        |selections| {
17860                            selections.clear_disjoint();
17861                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17862                        },
17863                    );
17864                }
17865                editor.highlight_background::<Self>(
17866                    &ranges,
17867                    |_, theme| theme.colors().editor_highlighted_line_background,
17868                    cx,
17869                );
17870            }
17871            MultibufferSelectionMode::All => {
17872                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17873                    selections.clear_disjoint();
17874                    selections.select_anchor_ranges(ranges);
17875                });
17876            }
17877        });
17878
17879        let item = Box::new(editor);
17880
17881        let pane = if split {
17882            workspace.adjacent_pane(window, cx)
17883        } else {
17884            workspace.active_pane().clone()
17885        };
17886        let activate_pane = split;
17887
17888        let mut destination_index = None;
17889        pane.update(cx, |pane, cx| {
17890            if allow_preview && !was_existing {
17891                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
17892            }
17893            if was_existing && !allow_preview {
17894                pane.unpreview_item_if_preview(item.item_id());
17895            }
17896            pane.add_item(item, activate_pane, true, destination_index, window, cx);
17897        });
17898    }
17899
17900    pub fn rename(
17901        &mut self,
17902        _: &Rename,
17903        window: &mut Window,
17904        cx: &mut Context<Self>,
17905    ) -> Option<Task<Result<()>>> {
17906        use language::ToOffset as _;
17907
17908        let provider = self.semantics_provider.clone()?;
17909        let selection = self.selections.newest_anchor().clone();
17910        let (cursor_buffer, cursor_buffer_position) = self
17911            .buffer
17912            .read(cx)
17913            .text_anchor_for_position(selection.head(), cx)?;
17914        let (tail_buffer, cursor_buffer_position_end) = self
17915            .buffer
17916            .read(cx)
17917            .text_anchor_for_position(selection.tail(), cx)?;
17918        if tail_buffer != cursor_buffer {
17919            return None;
17920        }
17921
17922        let snapshot = cursor_buffer.read(cx).snapshot();
17923        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17924        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17925        let prepare_rename = provider
17926            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17927            .unwrap_or_else(|| Task::ready(Ok(None)));
17928        drop(snapshot);
17929
17930        Some(cx.spawn_in(window, async move |this, cx| {
17931            let rename_range = if let Some(range) = prepare_rename.await? {
17932                Some(range)
17933            } else {
17934                this.update(cx, |this, cx| {
17935                    let buffer = this.buffer.read(cx).snapshot(cx);
17936                    let mut buffer_highlights = this
17937                        .document_highlights_for_position(selection.head(), &buffer)
17938                        .filter(|highlight| {
17939                            highlight.start.excerpt_id == selection.head().excerpt_id
17940                                && highlight.end.excerpt_id == selection.head().excerpt_id
17941                        });
17942                    buffer_highlights
17943                        .next()
17944                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17945                })?
17946            };
17947            if let Some(rename_range) = rename_range {
17948                this.update_in(cx, |this, window, cx| {
17949                    let snapshot = cursor_buffer.read(cx).snapshot();
17950                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17951                    let cursor_offset_in_rename_range =
17952                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17953                    let cursor_offset_in_rename_range_end =
17954                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17955
17956                    this.take_rename(false, window, cx);
17957                    let buffer = this.buffer.read(cx).read(cx);
17958                    let cursor_offset = selection.head().to_offset(&buffer);
17959                    let rename_start =
17960                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17961                    let rename_end = rename_start + rename_buffer_range.len();
17962                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17963                    let mut old_highlight_id = None;
17964                    let old_name: Arc<str> = buffer
17965                        .chunks(rename_start..rename_end, true)
17966                        .map(|chunk| {
17967                            if old_highlight_id.is_none() {
17968                                old_highlight_id = chunk.syntax_highlight_id;
17969                            }
17970                            chunk.text
17971                        })
17972                        .collect::<String>()
17973                        .into();
17974
17975                    drop(buffer);
17976
17977                    // Position the selection in the rename editor so that it matches the current selection.
17978                    this.show_local_selections = false;
17979                    let rename_editor = cx.new(|cx| {
17980                        let mut editor = Editor::single_line(window, cx);
17981                        editor.buffer.update(cx, |buffer, cx| {
17982                            buffer.edit(
17983                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
17984                                None,
17985                                cx,
17986                            )
17987                        });
17988                        let cursor_offset_in_rename_range =
17989                            MultiBufferOffset(cursor_offset_in_rename_range);
17990                        let cursor_offset_in_rename_range_end =
17991                            MultiBufferOffset(cursor_offset_in_rename_range_end);
17992                        let rename_selection_range = match cursor_offset_in_rename_range
17993                            .cmp(&cursor_offset_in_rename_range_end)
17994                        {
17995                            Ordering::Equal => {
17996                                editor.select_all(&SelectAll, window, cx);
17997                                return editor;
17998                            }
17999                            Ordering::Less => {
18000                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18001                            }
18002                            Ordering::Greater => {
18003                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18004                            }
18005                        };
18006                        if rename_selection_range.end.0 > old_name.len() {
18007                            editor.select_all(&SelectAll, window, cx);
18008                        } else {
18009                            editor.change_selections(Default::default(), window, cx, |s| {
18010                                s.select_ranges([rename_selection_range]);
18011                            });
18012                        }
18013                        editor
18014                    });
18015                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18016                        if e == &EditorEvent::Focused {
18017                            cx.emit(EditorEvent::FocusedIn)
18018                        }
18019                    })
18020                    .detach();
18021
18022                    let write_highlights =
18023                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18024                    let read_highlights =
18025                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18026                    let ranges = write_highlights
18027                        .iter()
18028                        .flat_map(|(_, ranges)| ranges.iter())
18029                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18030                        .cloned()
18031                        .collect();
18032
18033                    this.highlight_text::<Rename>(
18034                        ranges,
18035                        HighlightStyle {
18036                            fade_out: Some(0.6),
18037                            ..Default::default()
18038                        },
18039                        cx,
18040                    );
18041                    let rename_focus_handle = rename_editor.focus_handle(cx);
18042                    window.focus(&rename_focus_handle);
18043                    let block_id = this.insert_blocks(
18044                        [BlockProperties {
18045                            style: BlockStyle::Flex,
18046                            placement: BlockPlacement::Below(range.start),
18047                            height: Some(1),
18048                            render: Arc::new({
18049                                let rename_editor = rename_editor.clone();
18050                                move |cx: &mut BlockContext| {
18051                                    let mut text_style = cx.editor_style.text.clone();
18052                                    if let Some(highlight_style) = old_highlight_id
18053                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18054                                    {
18055                                        text_style = text_style.highlight(highlight_style);
18056                                    }
18057                                    div()
18058                                        .block_mouse_except_scroll()
18059                                        .pl(cx.anchor_x)
18060                                        .child(EditorElement::new(
18061                                            &rename_editor,
18062                                            EditorStyle {
18063                                                background: cx.theme().system().transparent,
18064                                                local_player: cx.editor_style.local_player,
18065                                                text: text_style,
18066                                                scrollbar_width: cx.editor_style.scrollbar_width,
18067                                                syntax: cx.editor_style.syntax.clone(),
18068                                                status: cx.editor_style.status.clone(),
18069                                                inlay_hints_style: HighlightStyle {
18070                                                    font_weight: Some(FontWeight::BOLD),
18071                                                    ..make_inlay_hints_style(cx.app)
18072                                                },
18073                                                edit_prediction_styles: make_suggestion_styles(
18074                                                    cx.app,
18075                                                ),
18076                                                ..EditorStyle::default()
18077                                            },
18078                                        ))
18079                                        .into_any_element()
18080                                }
18081                            }),
18082                            priority: 0,
18083                        }],
18084                        Some(Autoscroll::fit()),
18085                        cx,
18086                    )[0];
18087                    this.pending_rename = Some(RenameState {
18088                        range,
18089                        old_name,
18090                        editor: rename_editor,
18091                        block_id,
18092                    });
18093                })?;
18094            }
18095
18096            Ok(())
18097        }))
18098    }
18099
18100    pub fn confirm_rename(
18101        &mut self,
18102        _: &ConfirmRename,
18103        window: &mut Window,
18104        cx: &mut Context<Self>,
18105    ) -> Option<Task<Result<()>>> {
18106        let rename = self.take_rename(false, window, cx)?;
18107        let workspace = self.workspace()?.downgrade();
18108        let (buffer, start) = self
18109            .buffer
18110            .read(cx)
18111            .text_anchor_for_position(rename.range.start, cx)?;
18112        let (end_buffer, _) = self
18113            .buffer
18114            .read(cx)
18115            .text_anchor_for_position(rename.range.end, cx)?;
18116        if buffer != end_buffer {
18117            return None;
18118        }
18119
18120        let old_name = rename.old_name;
18121        let new_name = rename.editor.read(cx).text(cx);
18122
18123        let rename = self.semantics_provider.as_ref()?.perform_rename(
18124            &buffer,
18125            start,
18126            new_name.clone(),
18127            cx,
18128        )?;
18129
18130        Some(cx.spawn_in(window, async move |editor, cx| {
18131            let project_transaction = rename.await?;
18132            Self::open_project_transaction(
18133                &editor,
18134                workspace,
18135                project_transaction,
18136                format!("Rename: {}{}", old_name, new_name),
18137                cx,
18138            )
18139            .await?;
18140
18141            editor.update(cx, |editor, cx| {
18142                editor.refresh_document_highlights(cx);
18143            })?;
18144            Ok(())
18145        }))
18146    }
18147
18148    fn take_rename(
18149        &mut self,
18150        moving_cursor: bool,
18151        window: &mut Window,
18152        cx: &mut Context<Self>,
18153    ) -> Option<RenameState> {
18154        let rename = self.pending_rename.take()?;
18155        if rename.editor.focus_handle(cx).is_focused(window) {
18156            window.focus(&self.focus_handle);
18157        }
18158
18159        self.remove_blocks(
18160            [rename.block_id].into_iter().collect(),
18161            Some(Autoscroll::fit()),
18162            cx,
18163        );
18164        self.clear_highlights::<Rename>(cx);
18165        self.show_local_selections = true;
18166
18167        if moving_cursor {
18168            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18169                editor
18170                    .selections
18171                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18172                    .head()
18173            });
18174
18175            // Update the selection to match the position of the selection inside
18176            // the rename editor.
18177            let snapshot = self.buffer.read(cx).read(cx);
18178            let rename_range = rename.range.to_offset(&snapshot);
18179            let cursor_in_editor = snapshot
18180                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18181                .min(rename_range.end);
18182            drop(snapshot);
18183
18184            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18185                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18186            });
18187        } else {
18188            self.refresh_document_highlights(cx);
18189        }
18190
18191        Some(rename)
18192    }
18193
18194    pub fn pending_rename(&self) -> Option<&RenameState> {
18195        self.pending_rename.as_ref()
18196    }
18197
18198    fn format(
18199        &mut self,
18200        _: &Format,
18201        window: &mut Window,
18202        cx: &mut Context<Self>,
18203    ) -> Option<Task<Result<()>>> {
18204        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18205
18206        let project = match &self.project {
18207            Some(project) => project.clone(),
18208            None => return None,
18209        };
18210
18211        Some(self.perform_format(
18212            project,
18213            FormatTrigger::Manual,
18214            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18215            window,
18216            cx,
18217        ))
18218    }
18219
18220    fn format_selections(
18221        &mut self,
18222        _: &FormatSelections,
18223        window: &mut Window,
18224        cx: &mut Context<Self>,
18225    ) -> Option<Task<Result<()>>> {
18226        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18227
18228        let project = match &self.project {
18229            Some(project) => project.clone(),
18230            None => return None,
18231        };
18232
18233        let ranges = self
18234            .selections
18235            .all_adjusted(&self.display_snapshot(cx))
18236            .into_iter()
18237            .map(|selection| selection.range())
18238            .collect_vec();
18239
18240        Some(self.perform_format(
18241            project,
18242            FormatTrigger::Manual,
18243            FormatTarget::Ranges(ranges),
18244            window,
18245            cx,
18246        ))
18247    }
18248
18249    fn perform_format(
18250        &mut self,
18251        project: Entity<Project>,
18252        trigger: FormatTrigger,
18253        target: FormatTarget,
18254        window: &mut Window,
18255        cx: &mut Context<Self>,
18256    ) -> Task<Result<()>> {
18257        let buffer = self.buffer.clone();
18258        let (buffers, target) = match target {
18259            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18260            FormatTarget::Ranges(selection_ranges) => {
18261                let multi_buffer = buffer.read(cx);
18262                let snapshot = multi_buffer.read(cx);
18263                let mut buffers = HashSet::default();
18264                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18265                    BTreeMap::new();
18266                for selection_range in selection_ranges {
18267                    for (buffer, buffer_range, _) in
18268                        snapshot.range_to_buffer_ranges(selection_range)
18269                    {
18270                        let buffer_id = buffer.remote_id();
18271                        let start = buffer.anchor_before(buffer_range.start);
18272                        let end = buffer.anchor_after(buffer_range.end);
18273                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18274                        buffer_id_to_ranges
18275                            .entry(buffer_id)
18276                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18277                            .or_insert_with(|| vec![start..end]);
18278                    }
18279                }
18280                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18281            }
18282        };
18283
18284        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18285        let selections_prev = transaction_id_prev
18286            .and_then(|transaction_id_prev| {
18287                // default to selections as they were after the last edit, if we have them,
18288                // instead of how they are now.
18289                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18290                // will take you back to where you made the last edit, instead of staying where you scrolled
18291                self.selection_history
18292                    .transaction(transaction_id_prev)
18293                    .map(|t| t.0.clone())
18294            })
18295            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18296
18297        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18298        let format = project.update(cx, |project, cx| {
18299            project.format(buffers, target, true, trigger, cx)
18300        });
18301
18302        cx.spawn_in(window, async move |editor, cx| {
18303            let transaction = futures::select_biased! {
18304                transaction = format.log_err().fuse() => transaction,
18305                () = timeout => {
18306                    log::warn!("timed out waiting for formatting");
18307                    None
18308                }
18309            };
18310
18311            buffer
18312                .update(cx, |buffer, cx| {
18313                    if let Some(transaction) = transaction
18314                        && !buffer.is_singleton()
18315                    {
18316                        buffer.push_transaction(&transaction.0, cx);
18317                    }
18318                    cx.notify();
18319                })
18320                .ok();
18321
18322            if let Some(transaction_id_now) =
18323                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
18324            {
18325                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18326                if has_new_transaction {
18327                    _ = editor.update(cx, |editor, _| {
18328                        editor
18329                            .selection_history
18330                            .insert_transaction(transaction_id_now, selections_prev);
18331                    });
18332                }
18333            }
18334
18335            Ok(())
18336        })
18337    }
18338
18339    fn organize_imports(
18340        &mut self,
18341        _: &OrganizeImports,
18342        window: &mut Window,
18343        cx: &mut Context<Self>,
18344    ) -> Option<Task<Result<()>>> {
18345        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18346        let project = match &self.project {
18347            Some(project) => project.clone(),
18348            None => return None,
18349        };
18350        Some(self.perform_code_action_kind(
18351            project,
18352            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18353            window,
18354            cx,
18355        ))
18356    }
18357
18358    fn perform_code_action_kind(
18359        &mut self,
18360        project: Entity<Project>,
18361        kind: CodeActionKind,
18362        window: &mut Window,
18363        cx: &mut Context<Self>,
18364    ) -> Task<Result<()>> {
18365        let buffer = self.buffer.clone();
18366        let buffers = buffer.read(cx).all_buffers();
18367        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18368        let apply_action = project.update(cx, |project, cx| {
18369            project.apply_code_action_kind(buffers, kind, true, cx)
18370        });
18371        cx.spawn_in(window, async move |_, cx| {
18372            let transaction = futures::select_biased! {
18373                () = timeout => {
18374                    log::warn!("timed out waiting for executing code action");
18375                    None
18376                }
18377                transaction = apply_action.log_err().fuse() => transaction,
18378            };
18379            buffer
18380                .update(cx, |buffer, cx| {
18381                    // check if we need this
18382                    if let Some(transaction) = transaction
18383                        && !buffer.is_singleton()
18384                    {
18385                        buffer.push_transaction(&transaction.0, cx);
18386                    }
18387                    cx.notify();
18388                })
18389                .ok();
18390            Ok(())
18391        })
18392    }
18393
18394    pub fn restart_language_server(
18395        &mut self,
18396        _: &RestartLanguageServer,
18397        _: &mut Window,
18398        cx: &mut Context<Self>,
18399    ) {
18400        if let Some(project) = self.project.clone() {
18401            self.buffer.update(cx, |multi_buffer, cx| {
18402                project.update(cx, |project, cx| {
18403                    project.restart_language_servers_for_buffers(
18404                        multi_buffer.all_buffers().into_iter().collect(),
18405                        HashSet::default(),
18406                        cx,
18407                    );
18408                });
18409            })
18410        }
18411    }
18412
18413    pub fn stop_language_server(
18414        &mut self,
18415        _: &StopLanguageServer,
18416        _: &mut Window,
18417        cx: &mut Context<Self>,
18418    ) {
18419        if let Some(project) = self.project.clone() {
18420            self.buffer.update(cx, |multi_buffer, cx| {
18421                project.update(cx, |project, cx| {
18422                    project.stop_language_servers_for_buffers(
18423                        multi_buffer.all_buffers().into_iter().collect(),
18424                        HashSet::default(),
18425                        cx,
18426                    );
18427                });
18428            });
18429            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18430        }
18431    }
18432
18433    fn cancel_language_server_work(
18434        workspace: &mut Workspace,
18435        _: &actions::CancelLanguageServerWork,
18436        _: &mut Window,
18437        cx: &mut Context<Workspace>,
18438    ) {
18439        let project = workspace.project();
18440        let buffers = workspace
18441            .active_item(cx)
18442            .and_then(|item| item.act_as::<Editor>(cx))
18443            .map_or(HashSet::default(), |editor| {
18444                editor.read(cx).buffer.read(cx).all_buffers()
18445            });
18446        project.update(cx, |project, cx| {
18447            project.cancel_language_server_work_for_buffers(buffers, cx);
18448        });
18449    }
18450
18451    fn show_character_palette(
18452        &mut self,
18453        _: &ShowCharacterPalette,
18454        window: &mut Window,
18455        _: &mut Context<Self>,
18456    ) {
18457        window.show_character_palette();
18458    }
18459
18460    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18461        if !self.diagnostics_enabled() {
18462            return;
18463        }
18464
18465        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18466            let buffer = self.buffer.read(cx).snapshot(cx);
18467            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18468            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18469            let is_valid = buffer
18470                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18471                .any(|entry| {
18472                    entry.diagnostic.is_primary
18473                        && !entry.range.is_empty()
18474                        && entry.range.start == primary_range_start
18475                        && entry.diagnostic.message == active_diagnostics.active_message
18476                });
18477
18478            if !is_valid {
18479                self.dismiss_diagnostics(cx);
18480            }
18481        }
18482    }
18483
18484    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18485        match &self.active_diagnostics {
18486            ActiveDiagnostic::Group(group) => Some(group),
18487            _ => None,
18488        }
18489    }
18490
18491    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18492        if !self.diagnostics_enabled() {
18493            return;
18494        }
18495        self.dismiss_diagnostics(cx);
18496        self.active_diagnostics = ActiveDiagnostic::All;
18497    }
18498
18499    fn activate_diagnostics(
18500        &mut self,
18501        buffer_id: BufferId,
18502        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18503        window: &mut Window,
18504        cx: &mut Context<Self>,
18505    ) {
18506        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18507            return;
18508        }
18509        self.dismiss_diagnostics(cx);
18510        let snapshot = self.snapshot(window, cx);
18511        let buffer = self.buffer.read(cx).snapshot(cx);
18512        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18513            return;
18514        };
18515
18516        let diagnostic_group = buffer
18517            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18518            .collect::<Vec<_>>();
18519
18520        let language_registry = self
18521            .project()
18522            .map(|project| project.read(cx).languages().clone());
18523
18524        let blocks = renderer.render_group(
18525            diagnostic_group,
18526            buffer_id,
18527            snapshot,
18528            cx.weak_entity(),
18529            language_registry,
18530            cx,
18531        );
18532
18533        let blocks = self.display_map.update(cx, |display_map, cx| {
18534            display_map.insert_blocks(blocks, cx).into_iter().collect()
18535        });
18536        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18537            active_range: buffer.anchor_before(diagnostic.range.start)
18538                ..buffer.anchor_after(diagnostic.range.end),
18539            active_message: diagnostic.diagnostic.message.clone(),
18540            group_id: diagnostic.diagnostic.group_id,
18541            blocks,
18542        });
18543        cx.notify();
18544    }
18545
18546    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18547        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18548            return;
18549        };
18550
18551        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18552        if let ActiveDiagnostic::Group(group) = prev {
18553            self.display_map.update(cx, |display_map, cx| {
18554                display_map.remove_blocks(group.blocks, cx);
18555            });
18556            cx.notify();
18557        }
18558    }
18559
18560    /// Disable inline diagnostics rendering for this editor.
18561    pub fn disable_inline_diagnostics(&mut self) {
18562        self.inline_diagnostics_enabled = false;
18563        self.inline_diagnostics_update = Task::ready(());
18564        self.inline_diagnostics.clear();
18565    }
18566
18567    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18568        self.diagnostics_enabled = false;
18569        self.dismiss_diagnostics(cx);
18570        self.inline_diagnostics_update = Task::ready(());
18571        self.inline_diagnostics.clear();
18572    }
18573
18574    pub fn disable_word_completions(&mut self) {
18575        self.word_completions_enabled = false;
18576    }
18577
18578    pub fn diagnostics_enabled(&self) -> bool {
18579        self.diagnostics_enabled && self.mode.is_full()
18580    }
18581
18582    pub fn inline_diagnostics_enabled(&self) -> bool {
18583        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18584    }
18585
18586    pub fn show_inline_diagnostics(&self) -> bool {
18587        self.show_inline_diagnostics
18588    }
18589
18590    pub fn toggle_inline_diagnostics(
18591        &mut self,
18592        _: &ToggleInlineDiagnostics,
18593        window: &mut Window,
18594        cx: &mut Context<Editor>,
18595    ) {
18596        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18597        self.refresh_inline_diagnostics(false, window, cx);
18598    }
18599
18600    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18601        self.diagnostics_max_severity = severity;
18602        self.display_map.update(cx, |display_map, _| {
18603            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18604        });
18605    }
18606
18607    pub fn toggle_diagnostics(
18608        &mut self,
18609        _: &ToggleDiagnostics,
18610        window: &mut Window,
18611        cx: &mut Context<Editor>,
18612    ) {
18613        if !self.diagnostics_enabled() {
18614            return;
18615        }
18616
18617        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18618            EditorSettings::get_global(cx)
18619                .diagnostics_max_severity
18620                .filter(|severity| severity != &DiagnosticSeverity::Off)
18621                .unwrap_or(DiagnosticSeverity::Hint)
18622        } else {
18623            DiagnosticSeverity::Off
18624        };
18625        self.set_max_diagnostics_severity(new_severity, cx);
18626        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18627            self.active_diagnostics = ActiveDiagnostic::None;
18628            self.inline_diagnostics_update = Task::ready(());
18629            self.inline_diagnostics.clear();
18630        } else {
18631            self.refresh_inline_diagnostics(false, window, cx);
18632        }
18633
18634        cx.notify();
18635    }
18636
18637    pub fn toggle_minimap(
18638        &mut self,
18639        _: &ToggleMinimap,
18640        window: &mut Window,
18641        cx: &mut Context<Editor>,
18642    ) {
18643        if self.supports_minimap(cx) {
18644            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18645        }
18646    }
18647
18648    fn refresh_inline_diagnostics(
18649        &mut self,
18650        debounce: bool,
18651        window: &mut Window,
18652        cx: &mut Context<Self>,
18653    ) {
18654        let max_severity = ProjectSettings::get_global(cx)
18655            .diagnostics
18656            .inline
18657            .max_severity
18658            .unwrap_or(self.diagnostics_max_severity);
18659
18660        if !self.inline_diagnostics_enabled()
18661            || !self.diagnostics_enabled()
18662            || !self.show_inline_diagnostics
18663            || max_severity == DiagnosticSeverity::Off
18664        {
18665            self.inline_diagnostics_update = Task::ready(());
18666            self.inline_diagnostics.clear();
18667            return;
18668        }
18669
18670        let debounce_ms = ProjectSettings::get_global(cx)
18671            .diagnostics
18672            .inline
18673            .update_debounce_ms;
18674        let debounce = if debounce && debounce_ms > 0 {
18675            Some(Duration::from_millis(debounce_ms))
18676        } else {
18677            None
18678        };
18679        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18680            if let Some(debounce) = debounce {
18681                cx.background_executor().timer(debounce).await;
18682            }
18683            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18684                editor
18685                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18686                    .ok()
18687            }) else {
18688                return;
18689            };
18690
18691            let new_inline_diagnostics = cx
18692                .background_spawn(async move {
18693                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18694                    for diagnostic_entry in
18695                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18696                    {
18697                        let message = diagnostic_entry
18698                            .diagnostic
18699                            .message
18700                            .split_once('\n')
18701                            .map(|(line, _)| line)
18702                            .map(SharedString::new)
18703                            .unwrap_or_else(|| {
18704                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18705                            });
18706                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18707                        let (Ok(i) | Err(i)) = inline_diagnostics
18708                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18709                        inline_diagnostics.insert(
18710                            i,
18711                            (
18712                                start_anchor,
18713                                InlineDiagnostic {
18714                                    message,
18715                                    group_id: diagnostic_entry.diagnostic.group_id,
18716                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18717                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18718                                    severity: diagnostic_entry.diagnostic.severity,
18719                                },
18720                            ),
18721                        );
18722                    }
18723                    inline_diagnostics
18724                })
18725                .await;
18726
18727            editor
18728                .update(cx, |editor, cx| {
18729                    editor.inline_diagnostics = new_inline_diagnostics;
18730                    cx.notify();
18731                })
18732                .ok();
18733        });
18734    }
18735
18736    fn pull_diagnostics(
18737        &mut self,
18738        buffer_id: Option<BufferId>,
18739        window: &Window,
18740        cx: &mut Context<Self>,
18741    ) -> Option<()> {
18742        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18743            return None;
18744        }
18745        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18746            .diagnostics
18747            .lsp_pull_diagnostics;
18748        if !pull_diagnostics_settings.enabled {
18749            return None;
18750        }
18751        let project = self.project()?.downgrade();
18752
18753        let mut edited_buffer_ids = HashSet::default();
18754        let mut edited_worktree_ids = HashSet::default();
18755        let edited_buffers = match buffer_id {
18756            Some(buffer_id) => {
18757                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
18758                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
18759                edited_buffer_ids.insert(buffer.read(cx).remote_id());
18760                edited_worktree_ids.insert(worktree_id);
18761                vec![buffer]
18762            }
18763            None => self
18764                .buffer()
18765                .read(cx)
18766                .all_buffers()
18767                .into_iter()
18768                .filter(|buffer| {
18769                    let buffer = buffer.read(cx);
18770                    match buffer.file().map(|f| f.worktree_id(cx)) {
18771                        Some(worktree_id) => {
18772                            edited_buffer_ids.insert(buffer.remote_id());
18773                            edited_worktree_ids.insert(worktree_id);
18774                            true
18775                        }
18776                        None => false,
18777                    }
18778                })
18779                .collect::<Vec<_>>(),
18780        };
18781
18782        if edited_buffers.is_empty() {
18783            self.pull_diagnostics_task = Task::ready(());
18784            self.pull_diagnostics_background_task = Task::ready(());
18785            return None;
18786        }
18787
18788        let mut already_used_buffers = HashSet::default();
18789        let related_open_buffers = self
18790            .workspace
18791            .as_ref()
18792            .and_then(|(workspace, _)| workspace.upgrade())
18793            .into_iter()
18794            .flat_map(|workspace| workspace.read(cx).panes())
18795            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
18796            .filter(|editor| editor != &cx.entity())
18797            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
18798            .filter(|buffer| {
18799                let buffer = buffer.read(cx);
18800                let buffer_id = buffer.remote_id();
18801                if already_used_buffers.insert(buffer_id) {
18802                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
18803                        return !edited_buffer_ids.contains(&buffer_id)
18804                            && !edited_worktree_ids.contains(&worktree_id);
18805                    }
18806                }
18807                false
18808            })
18809            .collect::<Vec<_>>();
18810
18811        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18812        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
18813            if buffers.is_empty() {
18814                return Task::ready(());
18815            }
18816            let project_weak = project.clone();
18817            cx.spawn_in(window, async move |_, cx| {
18818                cx.background_executor().timer(delay).await;
18819
18820                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18821                    buffers
18822                        .into_iter()
18823                        .filter_map(|buffer| {
18824                            project_weak
18825                                .update(cx, |project, cx| {
18826                                    project.lsp_store().update(cx, |lsp_store, cx| {
18827                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18828                                    })
18829                                })
18830                                .ok()
18831                        })
18832                        .collect::<FuturesUnordered<_>>()
18833                }) else {
18834                    return;
18835                };
18836
18837                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18838                    if let Err(e) = pull_task {
18839                        log::error!("Failed to update project diagnostics: {e:#}");
18840                    }
18841                }
18842            })
18843        };
18844
18845        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
18846        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
18847
18848        Some(())
18849    }
18850
18851    pub fn set_selections_from_remote(
18852        &mut self,
18853        selections: Vec<Selection<Anchor>>,
18854        pending_selection: Option<Selection<Anchor>>,
18855        window: &mut Window,
18856        cx: &mut Context<Self>,
18857    ) {
18858        let old_cursor_position = self.selections.newest_anchor().head();
18859        self.selections
18860            .change_with(&self.display_snapshot(cx), |s| {
18861                s.select_anchors(selections);
18862                if let Some(pending_selection) = pending_selection {
18863                    s.set_pending(pending_selection, SelectMode::Character);
18864                } else {
18865                    s.clear_pending();
18866                }
18867            });
18868        self.selections_did_change(
18869            false,
18870            &old_cursor_position,
18871            SelectionEffects::default(),
18872            window,
18873            cx,
18874        );
18875    }
18876
18877    pub fn transact(
18878        &mut self,
18879        window: &mut Window,
18880        cx: &mut Context<Self>,
18881        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18882    ) -> Option<TransactionId> {
18883        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18884            this.start_transaction_at(Instant::now(), window, cx);
18885            update(this, window, cx);
18886            this.end_transaction_at(Instant::now(), cx)
18887        })
18888    }
18889
18890    pub fn start_transaction_at(
18891        &mut self,
18892        now: Instant,
18893        window: &mut Window,
18894        cx: &mut Context<Self>,
18895    ) -> Option<TransactionId> {
18896        self.end_selection(window, cx);
18897        if let Some(tx_id) = self
18898            .buffer
18899            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18900        {
18901            self.selection_history
18902                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18903            cx.emit(EditorEvent::TransactionBegun {
18904                transaction_id: tx_id,
18905            });
18906            Some(tx_id)
18907        } else {
18908            None
18909        }
18910    }
18911
18912    pub fn end_transaction_at(
18913        &mut self,
18914        now: Instant,
18915        cx: &mut Context<Self>,
18916    ) -> Option<TransactionId> {
18917        if let Some(transaction_id) = self
18918            .buffer
18919            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18920        {
18921            if let Some((_, end_selections)) =
18922                self.selection_history.transaction_mut(transaction_id)
18923            {
18924                *end_selections = Some(self.selections.disjoint_anchors_arc());
18925            } else {
18926                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18927            }
18928
18929            cx.emit(EditorEvent::Edited { transaction_id });
18930            Some(transaction_id)
18931        } else {
18932            None
18933        }
18934    }
18935
18936    pub fn modify_transaction_selection_history(
18937        &mut self,
18938        transaction_id: TransactionId,
18939        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18940    ) -> bool {
18941        self.selection_history
18942            .transaction_mut(transaction_id)
18943            .map(modify)
18944            .is_some()
18945    }
18946
18947    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18948        if self.selection_mark_mode {
18949            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18950                s.move_with(|_, sel| {
18951                    sel.collapse_to(sel.head(), SelectionGoal::None);
18952                });
18953            })
18954        }
18955        self.selection_mark_mode = true;
18956        cx.notify();
18957    }
18958
18959    pub fn swap_selection_ends(
18960        &mut self,
18961        _: &actions::SwapSelectionEnds,
18962        window: &mut Window,
18963        cx: &mut Context<Self>,
18964    ) {
18965        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18966            s.move_with(|_, sel| {
18967                if sel.start != sel.end {
18968                    sel.reversed = !sel.reversed
18969                }
18970            });
18971        });
18972        self.request_autoscroll(Autoscroll::newest(), cx);
18973        cx.notify();
18974    }
18975
18976    pub fn toggle_focus(
18977        workspace: &mut Workspace,
18978        _: &actions::ToggleFocus,
18979        window: &mut Window,
18980        cx: &mut Context<Workspace>,
18981    ) {
18982        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18983            return;
18984        };
18985        workspace.activate_item(&item, true, true, window, cx);
18986    }
18987
18988    pub fn toggle_fold(
18989        &mut self,
18990        _: &actions::ToggleFold,
18991        window: &mut Window,
18992        cx: &mut Context<Self>,
18993    ) {
18994        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18995            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18996            let selection = self.selections.newest::<Point>(&display_map);
18997
18998            let range = if selection.is_empty() {
18999                let point = selection.head().to_display_point(&display_map);
19000                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19001                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19002                    .to_point(&display_map);
19003                start..end
19004            } else {
19005                selection.range()
19006            };
19007            if display_map.folds_in_range(range).next().is_some() {
19008                self.unfold_lines(&Default::default(), window, cx)
19009            } else {
19010                self.fold(&Default::default(), window, cx)
19011            }
19012        } else {
19013            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19014            let buffer_ids: HashSet<_> = self
19015                .selections
19016                .disjoint_anchor_ranges()
19017                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19018                .collect();
19019
19020            let should_unfold = buffer_ids
19021                .iter()
19022                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19023
19024            for buffer_id in buffer_ids {
19025                if should_unfold {
19026                    self.unfold_buffer(buffer_id, cx);
19027                } else {
19028                    self.fold_buffer(buffer_id, cx);
19029                }
19030            }
19031        }
19032    }
19033
19034    pub fn toggle_fold_recursive(
19035        &mut self,
19036        _: &actions::ToggleFoldRecursive,
19037        window: &mut Window,
19038        cx: &mut Context<Self>,
19039    ) {
19040        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19041
19042        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19043        let range = if selection.is_empty() {
19044            let point = selection.head().to_display_point(&display_map);
19045            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19046            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19047                .to_point(&display_map);
19048            start..end
19049        } else {
19050            selection.range()
19051        };
19052        if display_map.folds_in_range(range).next().is_some() {
19053            self.unfold_recursive(&Default::default(), window, cx)
19054        } else {
19055            self.fold_recursive(&Default::default(), window, cx)
19056        }
19057    }
19058
19059    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19060        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19061            let mut to_fold = Vec::new();
19062            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19063            let selections = self.selections.all_adjusted(&display_map);
19064
19065            for selection in selections {
19066                let range = selection.range().sorted();
19067                let buffer_start_row = range.start.row;
19068
19069                if range.start.row != range.end.row {
19070                    let mut found = false;
19071                    let mut row = range.start.row;
19072                    while row <= range.end.row {
19073                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19074                        {
19075                            found = true;
19076                            row = crease.range().end.row + 1;
19077                            to_fold.push(crease);
19078                        } else {
19079                            row += 1
19080                        }
19081                    }
19082                    if found {
19083                        continue;
19084                    }
19085                }
19086
19087                for row in (0..=range.start.row).rev() {
19088                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19089                        && crease.range().end.row >= buffer_start_row
19090                    {
19091                        to_fold.push(crease);
19092                        if row <= range.start.row {
19093                            break;
19094                        }
19095                    }
19096                }
19097            }
19098
19099            self.fold_creases(to_fold, true, window, cx);
19100        } else {
19101            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19102            let buffer_ids = self
19103                .selections
19104                .disjoint_anchor_ranges()
19105                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19106                .collect::<HashSet<_>>();
19107            for buffer_id in buffer_ids {
19108                self.fold_buffer(buffer_id, cx);
19109            }
19110        }
19111    }
19112
19113    pub fn toggle_fold_all(
19114        &mut self,
19115        _: &actions::ToggleFoldAll,
19116        window: &mut Window,
19117        cx: &mut Context<Self>,
19118    ) {
19119        if self.buffer.read(cx).is_singleton() {
19120            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19121            let has_folds = display_map
19122                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19123                .next()
19124                .is_some();
19125
19126            if has_folds {
19127                self.unfold_all(&actions::UnfoldAll, window, cx);
19128            } else {
19129                self.fold_all(&actions::FoldAll, window, cx);
19130            }
19131        } else {
19132            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19133            let should_unfold = buffer_ids
19134                .iter()
19135                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19136
19137            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19138                editor
19139                    .update_in(cx, |editor, _, cx| {
19140                        for buffer_id in buffer_ids {
19141                            if should_unfold {
19142                                editor.unfold_buffer(buffer_id, cx);
19143                            } else {
19144                                editor.fold_buffer(buffer_id, cx);
19145                            }
19146                        }
19147                    })
19148                    .ok();
19149            });
19150        }
19151    }
19152
19153    fn fold_at_level(
19154        &mut self,
19155        fold_at: &FoldAtLevel,
19156        window: &mut Window,
19157        cx: &mut Context<Self>,
19158    ) {
19159        if !self.buffer.read(cx).is_singleton() {
19160            return;
19161        }
19162
19163        let fold_at_level = fold_at.0;
19164        let snapshot = self.buffer.read(cx).snapshot(cx);
19165        let mut to_fold = Vec::new();
19166        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19167
19168        let row_ranges_to_keep: Vec<Range<u32>> = self
19169            .selections
19170            .all::<Point>(&self.display_snapshot(cx))
19171            .into_iter()
19172            .map(|sel| sel.start.row..sel.end.row)
19173            .collect();
19174
19175        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19176            while start_row < end_row {
19177                match self
19178                    .snapshot(window, cx)
19179                    .crease_for_buffer_row(MultiBufferRow(start_row))
19180                {
19181                    Some(crease) => {
19182                        let nested_start_row = crease.range().start.row + 1;
19183                        let nested_end_row = crease.range().end.row;
19184
19185                        if current_level < fold_at_level {
19186                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19187                        } else if current_level == fold_at_level {
19188                            // Fold iff there is no selection completely contained within the fold region
19189                            if !row_ranges_to_keep.iter().any(|selection| {
19190                                selection.end >= nested_start_row
19191                                    && selection.start <= nested_end_row
19192                            }) {
19193                                to_fold.push(crease);
19194                            }
19195                        }
19196
19197                        start_row = nested_end_row + 1;
19198                    }
19199                    None => start_row += 1,
19200                }
19201            }
19202        }
19203
19204        self.fold_creases(to_fold, true, window, cx);
19205    }
19206
19207    pub fn fold_at_level_1(
19208        &mut self,
19209        _: &actions::FoldAtLevel1,
19210        window: &mut Window,
19211        cx: &mut Context<Self>,
19212    ) {
19213        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19214    }
19215
19216    pub fn fold_at_level_2(
19217        &mut self,
19218        _: &actions::FoldAtLevel2,
19219        window: &mut Window,
19220        cx: &mut Context<Self>,
19221    ) {
19222        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19223    }
19224
19225    pub fn fold_at_level_3(
19226        &mut self,
19227        _: &actions::FoldAtLevel3,
19228        window: &mut Window,
19229        cx: &mut Context<Self>,
19230    ) {
19231        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19232    }
19233
19234    pub fn fold_at_level_4(
19235        &mut self,
19236        _: &actions::FoldAtLevel4,
19237        window: &mut Window,
19238        cx: &mut Context<Self>,
19239    ) {
19240        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19241    }
19242
19243    pub fn fold_at_level_5(
19244        &mut self,
19245        _: &actions::FoldAtLevel5,
19246        window: &mut Window,
19247        cx: &mut Context<Self>,
19248    ) {
19249        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19250    }
19251
19252    pub fn fold_at_level_6(
19253        &mut self,
19254        _: &actions::FoldAtLevel6,
19255        window: &mut Window,
19256        cx: &mut Context<Self>,
19257    ) {
19258        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19259    }
19260
19261    pub fn fold_at_level_7(
19262        &mut self,
19263        _: &actions::FoldAtLevel7,
19264        window: &mut Window,
19265        cx: &mut Context<Self>,
19266    ) {
19267        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19268    }
19269
19270    pub fn fold_at_level_8(
19271        &mut self,
19272        _: &actions::FoldAtLevel8,
19273        window: &mut Window,
19274        cx: &mut Context<Self>,
19275    ) {
19276        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19277    }
19278
19279    pub fn fold_at_level_9(
19280        &mut self,
19281        _: &actions::FoldAtLevel9,
19282        window: &mut Window,
19283        cx: &mut Context<Self>,
19284    ) {
19285        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19286    }
19287
19288    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19289        if self.buffer.read(cx).is_singleton() {
19290            let mut fold_ranges = Vec::new();
19291            let snapshot = self.buffer.read(cx).snapshot(cx);
19292
19293            for row in 0..snapshot.max_row().0 {
19294                if let Some(foldable_range) = self
19295                    .snapshot(window, cx)
19296                    .crease_for_buffer_row(MultiBufferRow(row))
19297                {
19298                    fold_ranges.push(foldable_range);
19299                }
19300            }
19301
19302            self.fold_creases(fold_ranges, true, window, cx);
19303        } else {
19304            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19305                editor
19306                    .update_in(cx, |editor, _, cx| {
19307                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19308                            editor.fold_buffer(buffer_id, cx);
19309                        }
19310                    })
19311                    .ok();
19312            });
19313        }
19314    }
19315
19316    pub fn fold_function_bodies(
19317        &mut self,
19318        _: &actions::FoldFunctionBodies,
19319        window: &mut Window,
19320        cx: &mut Context<Self>,
19321    ) {
19322        let snapshot = self.buffer.read(cx).snapshot(cx);
19323
19324        let ranges = snapshot
19325            .text_object_ranges(
19326                MultiBufferOffset(0)..snapshot.len(),
19327                TreeSitterOptions::default(),
19328            )
19329            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19330            .collect::<Vec<_>>();
19331
19332        let creases = ranges
19333            .into_iter()
19334            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19335            .collect();
19336
19337        self.fold_creases(creases, true, window, cx);
19338    }
19339
19340    pub fn fold_recursive(
19341        &mut self,
19342        _: &actions::FoldRecursive,
19343        window: &mut Window,
19344        cx: &mut Context<Self>,
19345    ) {
19346        let mut to_fold = Vec::new();
19347        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19348        let selections = self.selections.all_adjusted(&display_map);
19349
19350        for selection in selections {
19351            let range = selection.range().sorted();
19352            let buffer_start_row = range.start.row;
19353
19354            if range.start.row != range.end.row {
19355                let mut found = false;
19356                for row in range.start.row..=range.end.row {
19357                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19358                        found = true;
19359                        to_fold.push(crease);
19360                    }
19361                }
19362                if found {
19363                    continue;
19364                }
19365            }
19366
19367            for row in (0..=range.start.row).rev() {
19368                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19369                    if crease.range().end.row >= buffer_start_row {
19370                        to_fold.push(crease);
19371                    } else {
19372                        break;
19373                    }
19374                }
19375            }
19376        }
19377
19378        self.fold_creases(to_fold, true, window, cx);
19379    }
19380
19381    pub fn fold_at(
19382        &mut self,
19383        buffer_row: MultiBufferRow,
19384        window: &mut Window,
19385        cx: &mut Context<Self>,
19386    ) {
19387        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19388
19389        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19390            let autoscroll = self
19391                .selections
19392                .all::<Point>(&display_map)
19393                .iter()
19394                .any(|selection| crease.range().overlaps(&selection.range()));
19395
19396            self.fold_creases(vec![crease], autoscroll, window, cx);
19397        }
19398    }
19399
19400    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19401        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19402            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19403            let buffer = display_map.buffer_snapshot();
19404            let selections = self.selections.all::<Point>(&display_map);
19405            let ranges = selections
19406                .iter()
19407                .map(|s| {
19408                    let range = s.display_range(&display_map).sorted();
19409                    let mut start = range.start.to_point(&display_map);
19410                    let mut end = range.end.to_point(&display_map);
19411                    start.column = 0;
19412                    end.column = buffer.line_len(MultiBufferRow(end.row));
19413                    start..end
19414                })
19415                .collect::<Vec<_>>();
19416
19417            self.unfold_ranges(&ranges, true, true, cx);
19418        } else {
19419            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19420            let buffer_ids = self
19421                .selections
19422                .disjoint_anchor_ranges()
19423                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19424                .collect::<HashSet<_>>();
19425            for buffer_id in buffer_ids {
19426                self.unfold_buffer(buffer_id, cx);
19427            }
19428        }
19429    }
19430
19431    pub fn unfold_recursive(
19432        &mut self,
19433        _: &UnfoldRecursive,
19434        _window: &mut Window,
19435        cx: &mut Context<Self>,
19436    ) {
19437        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19438        let selections = self.selections.all::<Point>(&display_map);
19439        let ranges = selections
19440            .iter()
19441            .map(|s| {
19442                let mut range = s.display_range(&display_map).sorted();
19443                *range.start.column_mut() = 0;
19444                *range.end.column_mut() = display_map.line_len(range.end.row());
19445                let start = range.start.to_point(&display_map);
19446                let end = range.end.to_point(&display_map);
19447                start..end
19448            })
19449            .collect::<Vec<_>>();
19450
19451        self.unfold_ranges(&ranges, true, true, cx);
19452    }
19453
19454    pub fn unfold_at(
19455        &mut self,
19456        buffer_row: MultiBufferRow,
19457        _window: &mut Window,
19458        cx: &mut Context<Self>,
19459    ) {
19460        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19461
19462        let intersection_range = Point::new(buffer_row.0, 0)
19463            ..Point::new(
19464                buffer_row.0,
19465                display_map.buffer_snapshot().line_len(buffer_row),
19466            );
19467
19468        let autoscroll = self
19469            .selections
19470            .all::<Point>(&display_map)
19471            .iter()
19472            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19473
19474        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19475    }
19476
19477    pub fn unfold_all(
19478        &mut self,
19479        _: &actions::UnfoldAll,
19480        _window: &mut Window,
19481        cx: &mut Context<Self>,
19482    ) {
19483        if self.buffer.read(cx).is_singleton() {
19484            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19485            self.unfold_ranges(
19486                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19487                true,
19488                true,
19489                cx,
19490            );
19491        } else {
19492            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19493                editor
19494                    .update(cx, |editor, cx| {
19495                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19496                            editor.unfold_buffer(buffer_id, cx);
19497                        }
19498                    })
19499                    .ok();
19500            });
19501        }
19502    }
19503
19504    pub fn fold_selected_ranges(
19505        &mut self,
19506        _: &FoldSelectedRanges,
19507        window: &mut Window,
19508        cx: &mut Context<Self>,
19509    ) {
19510        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19511        let selections = self.selections.all_adjusted(&display_map);
19512        let ranges = selections
19513            .into_iter()
19514            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19515            .collect::<Vec<_>>();
19516        self.fold_creases(ranges, true, window, cx);
19517    }
19518
19519    pub fn fold_ranges<T: ToOffset + Clone>(
19520        &mut self,
19521        ranges: Vec<Range<T>>,
19522        auto_scroll: bool,
19523        window: &mut Window,
19524        cx: &mut Context<Self>,
19525    ) {
19526        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19527        let ranges = ranges
19528            .into_iter()
19529            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19530            .collect::<Vec<_>>();
19531        self.fold_creases(ranges, auto_scroll, window, cx);
19532    }
19533
19534    pub fn fold_creases<T: ToOffset + Clone>(
19535        &mut self,
19536        creases: Vec<Crease<T>>,
19537        auto_scroll: bool,
19538        _window: &mut Window,
19539        cx: &mut Context<Self>,
19540    ) {
19541        if creases.is_empty() {
19542            return;
19543        }
19544
19545        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19546
19547        if auto_scroll {
19548            self.request_autoscroll(Autoscroll::fit(), cx);
19549        }
19550
19551        cx.notify();
19552
19553        self.scrollbar_marker_state.dirty = true;
19554        self.folds_did_change(cx);
19555    }
19556
19557    /// Removes any folds whose ranges intersect any of the given ranges.
19558    pub fn unfold_ranges<T: ToOffset + Clone>(
19559        &mut self,
19560        ranges: &[Range<T>],
19561        inclusive: bool,
19562        auto_scroll: bool,
19563        cx: &mut Context<Self>,
19564    ) {
19565        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19566            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19567        });
19568        self.folds_did_change(cx);
19569    }
19570
19571    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19572        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19573            return;
19574        }
19575
19576        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19577        self.display_map.update(cx, |display_map, cx| {
19578            display_map.fold_buffers([buffer_id], cx)
19579        });
19580
19581        let snapshot = self.display_snapshot(cx);
19582        self.selections.change_with(&snapshot, |selections| {
19583            selections.remove_selections_from_buffer(buffer_id);
19584        });
19585
19586        cx.emit(EditorEvent::BufferFoldToggled {
19587            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19588            folded: true,
19589        });
19590        cx.notify();
19591    }
19592
19593    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19594        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19595            return;
19596        }
19597        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19598        self.display_map.update(cx, |display_map, cx| {
19599            display_map.unfold_buffers([buffer_id], cx);
19600        });
19601        cx.emit(EditorEvent::BufferFoldToggled {
19602            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19603            folded: false,
19604        });
19605        cx.notify();
19606    }
19607
19608    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19609        self.display_map.read(cx).is_buffer_folded(buffer)
19610    }
19611
19612    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19613        self.display_map.read(cx).folded_buffers()
19614    }
19615
19616    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19617        self.display_map.update(cx, |display_map, cx| {
19618            display_map.disable_header_for_buffer(buffer_id, cx);
19619        });
19620        cx.notify();
19621    }
19622
19623    /// Removes any folds with the given ranges.
19624    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19625        &mut self,
19626        ranges: &[Range<T>],
19627        type_id: TypeId,
19628        auto_scroll: bool,
19629        cx: &mut Context<Self>,
19630    ) {
19631        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19632            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19633        });
19634        self.folds_did_change(cx);
19635    }
19636
19637    fn remove_folds_with<T: ToOffset + Clone>(
19638        &mut self,
19639        ranges: &[Range<T>],
19640        auto_scroll: bool,
19641        cx: &mut Context<Self>,
19642        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19643    ) {
19644        if ranges.is_empty() {
19645            return;
19646        }
19647
19648        let mut buffers_affected = HashSet::default();
19649        let multi_buffer = self.buffer().read(cx);
19650        for range in ranges {
19651            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19652                buffers_affected.insert(buffer.read(cx).remote_id());
19653            };
19654        }
19655
19656        self.display_map.update(cx, update);
19657
19658        if auto_scroll {
19659            self.request_autoscroll(Autoscroll::fit(), cx);
19660        }
19661
19662        cx.notify();
19663        self.scrollbar_marker_state.dirty = true;
19664        self.active_indent_guides_state.dirty = true;
19665    }
19666
19667    pub fn update_renderer_widths(
19668        &mut self,
19669        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19670        cx: &mut Context<Self>,
19671    ) -> bool {
19672        self.display_map
19673            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19674    }
19675
19676    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19677        self.display_map.read(cx).fold_placeholder.clone()
19678    }
19679
19680    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19681        self.use_base_text_line_numbers = show;
19682    }
19683
19684    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19685        self.buffer.update(cx, |buffer, cx| {
19686            buffer.set_all_diff_hunks_expanded(cx);
19687        });
19688    }
19689
19690    pub fn expand_all_diff_hunks(
19691        &mut self,
19692        _: &ExpandAllDiffHunks,
19693        _window: &mut Window,
19694        cx: &mut Context<Self>,
19695    ) {
19696        self.buffer.update(cx, |buffer, cx| {
19697            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19698        });
19699    }
19700
19701    pub fn collapse_all_diff_hunks(
19702        &mut self,
19703        _: &CollapseAllDiffHunks,
19704        _window: &mut Window,
19705        cx: &mut Context<Self>,
19706    ) {
19707        self.buffer.update(cx, |buffer, cx| {
19708            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19709        });
19710    }
19711
19712    pub fn toggle_selected_diff_hunks(
19713        &mut self,
19714        _: &ToggleSelectedDiffHunks,
19715        _window: &mut Window,
19716        cx: &mut Context<Self>,
19717    ) {
19718        let ranges: Vec<_> = self
19719            .selections
19720            .disjoint_anchors()
19721            .iter()
19722            .map(|s| s.range())
19723            .collect();
19724        self.toggle_diff_hunks_in_ranges(ranges, cx);
19725    }
19726
19727    pub fn diff_hunks_in_ranges<'a>(
19728        &'a self,
19729        ranges: &'a [Range<Anchor>],
19730        buffer: &'a MultiBufferSnapshot,
19731    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19732        ranges.iter().flat_map(move |range| {
19733            let end_excerpt_id = range.end.excerpt_id;
19734            let range = range.to_point(buffer);
19735            let mut peek_end = range.end;
19736            if range.end.row < buffer.max_row().0 {
19737                peek_end = Point::new(range.end.row + 1, 0);
19738            }
19739            buffer
19740                .diff_hunks_in_range(range.start..peek_end)
19741                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19742        })
19743    }
19744
19745    pub fn has_stageable_diff_hunks_in_ranges(
19746        &self,
19747        ranges: &[Range<Anchor>],
19748        snapshot: &MultiBufferSnapshot,
19749    ) -> bool {
19750        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19751        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19752    }
19753
19754    pub fn toggle_staged_selected_diff_hunks(
19755        &mut self,
19756        _: &::git::ToggleStaged,
19757        _: &mut Window,
19758        cx: &mut Context<Self>,
19759    ) {
19760        let snapshot = self.buffer.read(cx).snapshot(cx);
19761        let ranges: Vec<_> = self
19762            .selections
19763            .disjoint_anchors()
19764            .iter()
19765            .map(|s| s.range())
19766            .collect();
19767        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19768        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19769    }
19770
19771    pub fn set_render_diff_hunk_controls(
19772        &mut self,
19773        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19774        cx: &mut Context<Self>,
19775    ) {
19776        self.render_diff_hunk_controls = render_diff_hunk_controls;
19777        cx.notify();
19778    }
19779
19780    pub fn stage_and_next(
19781        &mut self,
19782        _: &::git::StageAndNext,
19783        window: &mut Window,
19784        cx: &mut Context<Self>,
19785    ) {
19786        self.do_stage_or_unstage_and_next(true, window, cx);
19787    }
19788
19789    pub fn unstage_and_next(
19790        &mut self,
19791        _: &::git::UnstageAndNext,
19792        window: &mut Window,
19793        cx: &mut Context<Self>,
19794    ) {
19795        self.do_stage_or_unstage_and_next(false, window, cx);
19796    }
19797
19798    pub fn stage_or_unstage_diff_hunks(
19799        &mut self,
19800        stage: bool,
19801        ranges: Vec<Range<Anchor>>,
19802        cx: &mut Context<Self>,
19803    ) {
19804        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19805        cx.spawn(async move |this, cx| {
19806            task.await?;
19807            this.update(cx, |this, cx| {
19808                let snapshot = this.buffer.read(cx).snapshot(cx);
19809                let chunk_by = this
19810                    .diff_hunks_in_ranges(&ranges, &snapshot)
19811                    .chunk_by(|hunk| hunk.buffer_id);
19812                for (buffer_id, hunks) in &chunk_by {
19813                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19814                }
19815            })
19816        })
19817        .detach_and_log_err(cx);
19818    }
19819
19820    fn save_buffers_for_ranges_if_needed(
19821        &mut self,
19822        ranges: &[Range<Anchor>],
19823        cx: &mut Context<Editor>,
19824    ) -> Task<Result<()>> {
19825        let multibuffer = self.buffer.read(cx);
19826        let snapshot = multibuffer.read(cx);
19827        let buffer_ids: HashSet<_> = ranges
19828            .iter()
19829            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19830            .collect();
19831        drop(snapshot);
19832
19833        let mut buffers = HashSet::default();
19834        for buffer_id in buffer_ids {
19835            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19836                let buffer = buffer_entity.read(cx);
19837                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19838                {
19839                    buffers.insert(buffer_entity);
19840                }
19841            }
19842        }
19843
19844        if let Some(project) = &self.project {
19845            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19846        } else {
19847            Task::ready(Ok(()))
19848        }
19849    }
19850
19851    fn do_stage_or_unstage_and_next(
19852        &mut self,
19853        stage: bool,
19854        window: &mut Window,
19855        cx: &mut Context<Self>,
19856    ) {
19857        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19858
19859        if ranges.iter().any(|range| range.start != range.end) {
19860            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19861            return;
19862        }
19863
19864        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19865        let snapshot = self.snapshot(window, cx);
19866        let position = self
19867            .selections
19868            .newest::<Point>(&snapshot.display_snapshot)
19869            .head();
19870        let mut row = snapshot
19871            .buffer_snapshot()
19872            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19873            .find(|hunk| hunk.row_range.start.0 > position.row)
19874            .map(|hunk| hunk.row_range.start);
19875
19876        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19877        // Outside of the project diff editor, wrap around to the beginning.
19878        if !all_diff_hunks_expanded {
19879            row = row.or_else(|| {
19880                snapshot
19881                    .buffer_snapshot()
19882                    .diff_hunks_in_range(Point::zero()..position)
19883                    .find(|hunk| hunk.row_range.end.0 < position.row)
19884                    .map(|hunk| hunk.row_range.start)
19885            });
19886        }
19887
19888        if let Some(row) = row {
19889            let destination = Point::new(row.0, 0);
19890            let autoscroll = Autoscroll::center();
19891
19892            self.unfold_ranges(&[destination..destination], false, false, cx);
19893            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19894                s.select_ranges([destination..destination]);
19895            });
19896        }
19897    }
19898
19899    fn do_stage_or_unstage(
19900        &self,
19901        stage: bool,
19902        buffer_id: BufferId,
19903        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19904        cx: &mut App,
19905    ) -> Option<()> {
19906        let project = self.project()?;
19907        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19908        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19909        let buffer_snapshot = buffer.read(cx).snapshot();
19910        let file_exists = buffer_snapshot
19911            .file()
19912            .is_some_and(|file| file.disk_state().exists());
19913        diff.update(cx, |diff, cx| {
19914            diff.stage_or_unstage_hunks(
19915                stage,
19916                &hunks
19917                    .map(|hunk| buffer_diff::DiffHunk {
19918                        buffer_range: hunk.buffer_range,
19919                        // We don't need to pass in word diffs here because they're only used for rendering and
19920                        // this function changes internal state
19921                        base_word_diffs: Vec::default(),
19922                        buffer_word_diffs: Vec::default(),
19923                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19924                            ..hunk.diff_base_byte_range.end.0,
19925                        secondary_status: hunk.secondary_status,
19926                        range: Point::zero()..Point::zero(), // unused
19927                    })
19928                    .collect::<Vec<_>>(),
19929                &buffer_snapshot,
19930                file_exists,
19931                cx,
19932            )
19933        });
19934        None
19935    }
19936
19937    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19938        let ranges: Vec<_> = self
19939            .selections
19940            .disjoint_anchors()
19941            .iter()
19942            .map(|s| s.range())
19943            .collect();
19944        self.buffer
19945            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19946    }
19947
19948    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19949        self.buffer.update(cx, |buffer, cx| {
19950            let ranges = vec![Anchor::min()..Anchor::max()];
19951            if !buffer.all_diff_hunks_expanded()
19952                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19953            {
19954                buffer.collapse_diff_hunks(ranges, cx);
19955                true
19956            } else {
19957                false
19958            }
19959        })
19960    }
19961
19962    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19963        if self.buffer.read(cx).all_diff_hunks_expanded() {
19964            return true;
19965        }
19966        let ranges = vec![Anchor::min()..Anchor::max()];
19967        self.buffer
19968            .read(cx)
19969            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19970    }
19971
19972    fn toggle_diff_hunks_in_ranges(
19973        &mut self,
19974        ranges: Vec<Range<Anchor>>,
19975        cx: &mut Context<Editor>,
19976    ) {
19977        self.buffer.update(cx, |buffer, cx| {
19978            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19979            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19980        })
19981    }
19982
19983    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19984        self.buffer.update(cx, |buffer, cx| {
19985            let snapshot = buffer.snapshot(cx);
19986            let excerpt_id = range.end.excerpt_id;
19987            let point_range = range.to_point(&snapshot);
19988            let expand = !buffer.single_hunk_is_expanded(range, cx);
19989            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19990        })
19991    }
19992
19993    pub(crate) fn apply_all_diff_hunks(
19994        &mut self,
19995        _: &ApplyAllDiffHunks,
19996        window: &mut Window,
19997        cx: &mut Context<Self>,
19998    ) {
19999        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20000
20001        let buffers = self.buffer.read(cx).all_buffers();
20002        for branch_buffer in buffers {
20003            branch_buffer.update(cx, |branch_buffer, cx| {
20004                branch_buffer.merge_into_base(Vec::new(), cx);
20005            });
20006        }
20007
20008        if let Some(project) = self.project.clone() {
20009            self.save(
20010                SaveOptions {
20011                    format: true,
20012                    autosave: false,
20013                },
20014                project,
20015                window,
20016                cx,
20017            )
20018            .detach_and_log_err(cx);
20019        }
20020    }
20021
20022    pub(crate) fn apply_selected_diff_hunks(
20023        &mut self,
20024        _: &ApplyDiffHunk,
20025        window: &mut Window,
20026        cx: &mut Context<Self>,
20027    ) {
20028        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20029        let snapshot = self.snapshot(window, cx);
20030        let hunks = snapshot.hunks_for_ranges(
20031            self.selections
20032                .all(&snapshot.display_snapshot)
20033                .into_iter()
20034                .map(|selection| selection.range()),
20035        );
20036        let mut ranges_by_buffer = HashMap::default();
20037        self.transact(window, cx, |editor, _window, cx| {
20038            for hunk in hunks {
20039                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20040                    ranges_by_buffer
20041                        .entry(buffer.clone())
20042                        .or_insert_with(Vec::new)
20043                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20044                }
20045            }
20046
20047            for (buffer, ranges) in ranges_by_buffer {
20048                buffer.update(cx, |buffer, cx| {
20049                    buffer.merge_into_base(ranges, cx);
20050                });
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 fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20069        if hovered != self.gutter_hovered {
20070            self.gutter_hovered = hovered;
20071            cx.notify();
20072        }
20073    }
20074
20075    pub fn insert_blocks(
20076        &mut self,
20077        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20078        autoscroll: Option<Autoscroll>,
20079        cx: &mut Context<Self>,
20080    ) -> Vec<CustomBlockId> {
20081        let blocks = self
20082            .display_map
20083            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20084        if let Some(autoscroll) = autoscroll {
20085            self.request_autoscroll(autoscroll, cx);
20086        }
20087        cx.notify();
20088        blocks
20089    }
20090
20091    pub fn resize_blocks(
20092        &mut self,
20093        heights: HashMap<CustomBlockId, u32>,
20094        autoscroll: Option<Autoscroll>,
20095        cx: &mut Context<Self>,
20096    ) {
20097        self.display_map
20098            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20099        if let Some(autoscroll) = autoscroll {
20100            self.request_autoscroll(autoscroll, cx);
20101        }
20102        cx.notify();
20103    }
20104
20105    pub fn replace_blocks(
20106        &mut self,
20107        renderers: HashMap<CustomBlockId, RenderBlock>,
20108        autoscroll: Option<Autoscroll>,
20109        cx: &mut Context<Self>,
20110    ) {
20111        self.display_map
20112            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20113        if let Some(autoscroll) = autoscroll {
20114            self.request_autoscroll(autoscroll, cx);
20115        }
20116        cx.notify();
20117    }
20118
20119    pub fn remove_blocks(
20120        &mut self,
20121        block_ids: HashSet<CustomBlockId>,
20122        autoscroll: Option<Autoscroll>,
20123        cx: &mut Context<Self>,
20124    ) {
20125        self.display_map.update(cx, |display_map, cx| {
20126            display_map.remove_blocks(block_ids, cx)
20127        });
20128        if let Some(autoscroll) = autoscroll {
20129            self.request_autoscroll(autoscroll, cx);
20130        }
20131        cx.notify();
20132    }
20133
20134    pub fn row_for_block(
20135        &self,
20136        block_id: CustomBlockId,
20137        cx: &mut Context<Self>,
20138    ) -> Option<DisplayRow> {
20139        self.display_map
20140            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20141    }
20142
20143    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20144        self.focused_block = Some(focused_block);
20145    }
20146
20147    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20148        self.focused_block.take()
20149    }
20150
20151    pub fn insert_creases(
20152        &mut self,
20153        creases: impl IntoIterator<Item = Crease<Anchor>>,
20154        cx: &mut Context<Self>,
20155    ) -> Vec<CreaseId> {
20156        self.display_map
20157            .update(cx, |map, cx| map.insert_creases(creases, cx))
20158    }
20159
20160    pub fn remove_creases(
20161        &mut self,
20162        ids: impl IntoIterator<Item = CreaseId>,
20163        cx: &mut Context<Self>,
20164    ) -> Vec<(CreaseId, Range<Anchor>)> {
20165        self.display_map
20166            .update(cx, |map, cx| map.remove_creases(ids, cx))
20167    }
20168
20169    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20170        self.display_map
20171            .update(cx, |map, cx| map.snapshot(cx))
20172            .longest_row()
20173    }
20174
20175    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20176        self.display_map
20177            .update(cx, |map, cx| map.snapshot(cx))
20178            .max_point()
20179    }
20180
20181    pub fn text(&self, cx: &App) -> String {
20182        self.buffer.read(cx).read(cx).text()
20183    }
20184
20185    pub fn is_empty(&self, cx: &App) -> bool {
20186        self.buffer.read(cx).read(cx).is_empty()
20187    }
20188
20189    pub fn text_option(&self, cx: &App) -> Option<String> {
20190        let text = self.text(cx);
20191        let text = text.trim();
20192
20193        if text.is_empty() {
20194            return None;
20195        }
20196
20197        Some(text.to_string())
20198    }
20199
20200    pub fn set_text(
20201        &mut self,
20202        text: impl Into<Arc<str>>,
20203        window: &mut Window,
20204        cx: &mut Context<Self>,
20205    ) {
20206        self.transact(window, cx, |this, _, cx| {
20207            this.buffer
20208                .read(cx)
20209                .as_singleton()
20210                .expect("you can only call set_text on editors for singleton buffers")
20211                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20212        });
20213    }
20214
20215    pub fn display_text(&self, cx: &mut App) -> String {
20216        self.display_map
20217            .update(cx, |map, cx| map.snapshot(cx))
20218            .text()
20219    }
20220
20221    fn create_minimap(
20222        &self,
20223        minimap_settings: MinimapSettings,
20224        window: &mut Window,
20225        cx: &mut Context<Self>,
20226    ) -> Option<Entity<Self>> {
20227        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20228            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20229    }
20230
20231    fn initialize_new_minimap(
20232        &self,
20233        minimap_settings: MinimapSettings,
20234        window: &mut Window,
20235        cx: &mut Context<Self>,
20236    ) -> Entity<Self> {
20237        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20238
20239        let mut minimap = Editor::new_internal(
20240            EditorMode::Minimap {
20241                parent: cx.weak_entity(),
20242            },
20243            self.buffer.clone(),
20244            None,
20245            Some(self.display_map.clone()),
20246            window,
20247            cx,
20248        );
20249        minimap.scroll_manager.clone_state(&self.scroll_manager);
20250        minimap.set_text_style_refinement(TextStyleRefinement {
20251            font_size: Some(MINIMAP_FONT_SIZE),
20252            font_weight: Some(MINIMAP_FONT_WEIGHT),
20253            ..Default::default()
20254        });
20255        minimap.update_minimap_configuration(minimap_settings, cx);
20256        cx.new(|_| minimap)
20257    }
20258
20259    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20260        let current_line_highlight = minimap_settings
20261            .current_line_highlight
20262            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20263        self.set_current_line_highlight(Some(current_line_highlight));
20264    }
20265
20266    pub fn minimap(&self) -> Option<&Entity<Self>> {
20267        self.minimap
20268            .as_ref()
20269            .filter(|_| self.minimap_visibility.visible())
20270    }
20271
20272    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20273        let mut wrap_guides = smallvec![];
20274
20275        if self.show_wrap_guides == Some(false) {
20276            return wrap_guides;
20277        }
20278
20279        let settings = self.buffer.read(cx).language_settings(cx);
20280        if settings.show_wrap_guides {
20281            match self.soft_wrap_mode(cx) {
20282                SoftWrap::Column(soft_wrap) => {
20283                    wrap_guides.push((soft_wrap as usize, true));
20284                }
20285                SoftWrap::Bounded(soft_wrap) => {
20286                    wrap_guides.push((soft_wrap as usize, true));
20287                }
20288                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20289            }
20290            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20291        }
20292
20293        wrap_guides
20294    }
20295
20296    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20297        let settings = self.buffer.read(cx).language_settings(cx);
20298        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20299        match mode {
20300            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20301                SoftWrap::None
20302            }
20303            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20304            language_settings::SoftWrap::PreferredLineLength => {
20305                SoftWrap::Column(settings.preferred_line_length)
20306            }
20307            language_settings::SoftWrap::Bounded => {
20308                SoftWrap::Bounded(settings.preferred_line_length)
20309            }
20310        }
20311    }
20312
20313    pub fn set_soft_wrap_mode(
20314        &mut self,
20315        mode: language_settings::SoftWrap,
20316
20317        cx: &mut Context<Self>,
20318    ) {
20319        self.soft_wrap_mode_override = Some(mode);
20320        cx.notify();
20321    }
20322
20323    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20324        self.hard_wrap = hard_wrap;
20325        cx.notify();
20326    }
20327
20328    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20329        self.text_style_refinement = Some(style);
20330    }
20331
20332    /// called by the Element so we know what style we were most recently rendered with.
20333    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20334        // We intentionally do not inform the display map about the minimap style
20335        // so that wrapping is not recalculated and stays consistent for the editor
20336        // and its linked minimap.
20337        if !self.mode.is_minimap() {
20338            let font = style.text.font();
20339            let font_size = style.text.font_size.to_pixels(window.rem_size());
20340            let display_map = self
20341                .placeholder_display_map
20342                .as_ref()
20343                .filter(|_| self.is_empty(cx))
20344                .unwrap_or(&self.display_map);
20345
20346            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20347        }
20348        self.style = Some(style);
20349    }
20350
20351    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20352        if self.style.is_none() {
20353            self.style = Some(self.create_style(cx));
20354        }
20355        self.style.as_ref().unwrap()
20356    }
20357
20358    // Called by the element. This method is not designed to be called outside of the editor
20359    // element's layout code because it does not notify when rewrapping is computed synchronously.
20360    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20361        if self.is_empty(cx) {
20362            self.placeholder_display_map
20363                .as_ref()
20364                .map_or(false, |display_map| {
20365                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20366                })
20367        } else {
20368            self.display_map
20369                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20370        }
20371    }
20372
20373    pub fn set_soft_wrap(&mut self) {
20374        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20375    }
20376
20377    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20378        if self.soft_wrap_mode_override.is_some() {
20379            self.soft_wrap_mode_override.take();
20380        } else {
20381            let soft_wrap = match self.soft_wrap_mode(cx) {
20382                SoftWrap::GitDiff => return,
20383                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20384                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20385                    language_settings::SoftWrap::None
20386                }
20387            };
20388            self.soft_wrap_mode_override = Some(soft_wrap);
20389        }
20390        cx.notify();
20391    }
20392
20393    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20394        let Some(workspace) = self.workspace() else {
20395            return;
20396        };
20397        let fs = workspace.read(cx).app_state().fs.clone();
20398        let current_show = TabBarSettings::get_global(cx).show;
20399        update_settings_file(fs, cx, move |setting, _| {
20400            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20401        });
20402    }
20403
20404    pub fn toggle_indent_guides(
20405        &mut self,
20406        _: &ToggleIndentGuides,
20407        _: &mut Window,
20408        cx: &mut Context<Self>,
20409    ) {
20410        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20411            self.buffer
20412                .read(cx)
20413                .language_settings(cx)
20414                .indent_guides
20415                .enabled
20416        });
20417        self.show_indent_guides = Some(!currently_enabled);
20418        cx.notify();
20419    }
20420
20421    fn should_show_indent_guides(&self) -> Option<bool> {
20422        self.show_indent_guides
20423    }
20424
20425    pub fn disable_indent_guides_for_buffer(
20426        &mut self,
20427        buffer_id: BufferId,
20428        cx: &mut Context<Self>,
20429    ) {
20430        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20431        cx.notify();
20432    }
20433
20434    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20435        self.buffers_with_disabled_indent_guides
20436            .contains(&buffer_id)
20437    }
20438
20439    pub fn toggle_line_numbers(
20440        &mut self,
20441        _: &ToggleLineNumbers,
20442        _: &mut Window,
20443        cx: &mut Context<Self>,
20444    ) {
20445        let mut editor_settings = EditorSettings::get_global(cx).clone();
20446        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20447        EditorSettings::override_global(editor_settings, cx);
20448    }
20449
20450    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20451        if let Some(show_line_numbers) = self.show_line_numbers {
20452            return show_line_numbers;
20453        }
20454        EditorSettings::get_global(cx).gutter.line_numbers
20455    }
20456
20457    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
20458        match (
20459            self.use_relative_line_numbers,
20460            EditorSettings::get_global(cx).relative_line_numbers,
20461        ) {
20462            (None, setting) => setting,
20463            (Some(false), _) => RelativeLineNumbers::Disabled,
20464            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20465            (Some(true), _) => RelativeLineNumbers::Enabled,
20466        }
20467    }
20468
20469    pub fn toggle_relative_line_numbers(
20470        &mut self,
20471        _: &ToggleRelativeLineNumbers,
20472        _: &mut Window,
20473        cx: &mut Context<Self>,
20474    ) {
20475        let is_relative = self.relative_line_numbers(cx);
20476        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20477    }
20478
20479    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20480        self.use_relative_line_numbers = is_relative;
20481        cx.notify();
20482    }
20483
20484    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20485        self.show_gutter = show_gutter;
20486        cx.notify();
20487    }
20488
20489    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20490        self.show_scrollbars = ScrollbarAxes {
20491            horizontal: show,
20492            vertical: show,
20493        };
20494        cx.notify();
20495    }
20496
20497    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20498        self.show_scrollbars.vertical = show;
20499        cx.notify();
20500    }
20501
20502    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20503        self.show_scrollbars.horizontal = show;
20504        cx.notify();
20505    }
20506
20507    pub fn set_minimap_visibility(
20508        &mut self,
20509        minimap_visibility: MinimapVisibility,
20510        window: &mut Window,
20511        cx: &mut Context<Self>,
20512    ) {
20513        if self.minimap_visibility != minimap_visibility {
20514            if minimap_visibility.visible() && self.minimap.is_none() {
20515                let minimap_settings = EditorSettings::get_global(cx).minimap;
20516                self.minimap =
20517                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20518            }
20519            self.minimap_visibility = minimap_visibility;
20520            cx.notify();
20521        }
20522    }
20523
20524    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20525        self.set_show_scrollbars(false, cx);
20526        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20527    }
20528
20529    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20530        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20531    }
20532
20533    /// Normally the text in full mode and auto height editors is padded on the
20534    /// left side by roughly half a character width for improved hit testing.
20535    ///
20536    /// Use this method to disable this for cases where this is not wanted (e.g.
20537    /// if you want to align the editor text with some other text above or below)
20538    /// or if you want to add this padding to single-line editors.
20539    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20540        self.offset_content = offset_content;
20541        cx.notify();
20542    }
20543
20544    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20545        self.show_line_numbers = Some(show_line_numbers);
20546        cx.notify();
20547    }
20548
20549    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20550        self.disable_expand_excerpt_buttons = true;
20551        cx.notify();
20552    }
20553
20554    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20555        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20556        cx.notify();
20557    }
20558
20559    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20560        self.show_code_actions = Some(show_code_actions);
20561        cx.notify();
20562    }
20563
20564    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20565        self.show_runnables = Some(show_runnables);
20566        cx.notify();
20567    }
20568
20569    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20570        self.show_breakpoints = Some(show_breakpoints);
20571        cx.notify();
20572    }
20573
20574    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20575        if self.display_map.read(cx).masked != masked {
20576            self.display_map.update(cx, |map, _| map.masked = masked);
20577        }
20578        cx.notify()
20579    }
20580
20581    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20582        self.show_wrap_guides = Some(show_wrap_guides);
20583        cx.notify();
20584    }
20585
20586    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20587        self.show_indent_guides = Some(show_indent_guides);
20588        cx.notify();
20589    }
20590
20591    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20592        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20593            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20594                && let Some(dir) = file.abs_path(cx).parent()
20595            {
20596                return Some(dir.to_owned());
20597            }
20598        }
20599
20600        None
20601    }
20602
20603    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20604        self.active_excerpt(cx)?
20605            .1
20606            .read(cx)
20607            .file()
20608            .and_then(|f| f.as_local())
20609    }
20610
20611    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20612        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20613            let buffer = buffer.read(cx);
20614            if let Some(project_path) = buffer.project_path(cx) {
20615                let project = self.project()?.read(cx);
20616                project.absolute_path(&project_path, cx)
20617            } else {
20618                buffer
20619                    .file()
20620                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20621            }
20622        })
20623    }
20624
20625    pub fn reveal_in_finder(
20626        &mut self,
20627        _: &RevealInFileManager,
20628        _window: &mut Window,
20629        cx: &mut Context<Self>,
20630    ) {
20631        if let Some(target) = self.target_file(cx) {
20632            cx.reveal_path(&target.abs_path(cx));
20633        }
20634    }
20635
20636    pub fn copy_path(
20637        &mut self,
20638        _: &zed_actions::workspace::CopyPath,
20639        _window: &mut Window,
20640        cx: &mut Context<Self>,
20641    ) {
20642        if let Some(path) = self.target_file_abs_path(cx)
20643            && let Some(path) = path.to_str()
20644        {
20645            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20646        } else {
20647            cx.propagate();
20648        }
20649    }
20650
20651    pub fn copy_relative_path(
20652        &mut self,
20653        _: &zed_actions::workspace::CopyRelativePath,
20654        _window: &mut Window,
20655        cx: &mut Context<Self>,
20656    ) {
20657        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20658            let project = self.project()?.read(cx);
20659            let path = buffer.read(cx).file()?.path();
20660            let path = path.display(project.path_style(cx));
20661            Some(path)
20662        }) {
20663            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20664        } else {
20665            cx.propagate();
20666        }
20667    }
20668
20669    /// Returns the project path for the editor's buffer, if any buffer is
20670    /// opened in the editor.
20671    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20672        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20673            buffer.read(cx).project_path(cx)
20674        } else {
20675            None
20676        }
20677    }
20678
20679    // Returns true if the editor handled a go-to-line request
20680    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20681        maybe!({
20682            let breakpoint_store = self.breakpoint_store.as_ref()?;
20683
20684            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20685            else {
20686                self.clear_row_highlights::<ActiveDebugLine>();
20687                return None;
20688            };
20689
20690            let position = active_stack_frame.position;
20691            let buffer_id = position.buffer_id?;
20692            let snapshot = self
20693                .project
20694                .as_ref()?
20695                .read(cx)
20696                .buffer_for_id(buffer_id, cx)?
20697                .read(cx)
20698                .snapshot();
20699
20700            let mut handled = false;
20701            for (id, ExcerptRange { context, .. }) in
20702                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20703            {
20704                if context.start.cmp(&position, &snapshot).is_ge()
20705                    || context.end.cmp(&position, &snapshot).is_lt()
20706                {
20707                    continue;
20708                }
20709                let snapshot = self.buffer.read(cx).snapshot(cx);
20710                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20711
20712                handled = true;
20713                self.clear_row_highlights::<ActiveDebugLine>();
20714
20715                self.go_to_line::<ActiveDebugLine>(
20716                    multibuffer_anchor,
20717                    Some(cx.theme().colors().editor_debugger_active_line_background),
20718                    window,
20719                    cx,
20720                );
20721
20722                cx.notify();
20723            }
20724
20725            handled.then_some(())
20726        })
20727        .is_some()
20728    }
20729
20730    pub fn copy_file_name_without_extension(
20731        &mut self,
20732        _: &CopyFileNameWithoutExtension,
20733        _: &mut Window,
20734        cx: &mut Context<Self>,
20735    ) {
20736        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20737            let file = buffer.read(cx).file()?;
20738            file.path().file_stem()
20739        }) {
20740            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20741        }
20742    }
20743
20744    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20745        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20746            let file = buffer.read(cx).file()?;
20747            Some(file.file_name(cx))
20748        }) {
20749            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20750        }
20751    }
20752
20753    pub fn toggle_git_blame(
20754        &mut self,
20755        _: &::git::Blame,
20756        window: &mut Window,
20757        cx: &mut Context<Self>,
20758    ) {
20759        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20760
20761        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20762            self.start_git_blame(true, window, cx);
20763        }
20764
20765        cx.notify();
20766    }
20767
20768    pub fn toggle_git_blame_inline(
20769        &mut self,
20770        _: &ToggleGitBlameInline,
20771        window: &mut Window,
20772        cx: &mut Context<Self>,
20773    ) {
20774        self.toggle_git_blame_inline_internal(true, window, cx);
20775        cx.notify();
20776    }
20777
20778    pub fn open_git_blame_commit(
20779        &mut self,
20780        _: &OpenGitBlameCommit,
20781        window: &mut Window,
20782        cx: &mut Context<Self>,
20783    ) {
20784        self.open_git_blame_commit_internal(window, cx);
20785    }
20786
20787    fn open_git_blame_commit_internal(
20788        &mut self,
20789        window: &mut Window,
20790        cx: &mut Context<Self>,
20791    ) -> Option<()> {
20792        let blame = self.blame.as_ref()?;
20793        let snapshot = self.snapshot(window, cx);
20794        let cursor = self
20795            .selections
20796            .newest::<Point>(&snapshot.display_snapshot)
20797            .head();
20798        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20799        let (_, blame_entry) = blame
20800            .update(cx, |blame, cx| {
20801                blame
20802                    .blame_for_rows(
20803                        &[RowInfo {
20804                            buffer_id: Some(buffer.remote_id()),
20805                            buffer_row: Some(point.row),
20806                            ..Default::default()
20807                        }],
20808                        cx,
20809                    )
20810                    .next()
20811            })
20812            .flatten()?;
20813        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20814        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20815        let workspace = self.workspace()?.downgrade();
20816        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20817        None
20818    }
20819
20820    pub fn git_blame_inline_enabled(&self) -> bool {
20821        self.git_blame_inline_enabled
20822    }
20823
20824    pub fn toggle_selection_menu(
20825        &mut self,
20826        _: &ToggleSelectionMenu,
20827        _: &mut Window,
20828        cx: &mut Context<Self>,
20829    ) {
20830        self.show_selection_menu = self
20831            .show_selection_menu
20832            .map(|show_selections_menu| !show_selections_menu)
20833            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20834
20835        cx.notify();
20836    }
20837
20838    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20839        self.show_selection_menu
20840            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20841    }
20842
20843    fn start_git_blame(
20844        &mut self,
20845        user_triggered: bool,
20846        window: &mut Window,
20847        cx: &mut Context<Self>,
20848    ) {
20849        if let Some(project) = self.project() {
20850            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20851                && buffer.read(cx).file().is_none()
20852            {
20853                return;
20854            }
20855
20856            let focused = self.focus_handle(cx).contains_focused(window, cx);
20857
20858            let project = project.clone();
20859            let blame = cx
20860                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20861            self.blame_subscription =
20862                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20863            self.blame = Some(blame);
20864        }
20865    }
20866
20867    fn toggle_git_blame_inline_internal(
20868        &mut self,
20869        user_triggered: bool,
20870        window: &mut Window,
20871        cx: &mut Context<Self>,
20872    ) {
20873        if self.git_blame_inline_enabled {
20874            self.git_blame_inline_enabled = false;
20875            self.show_git_blame_inline = false;
20876            self.show_git_blame_inline_delay_task.take();
20877        } else {
20878            self.git_blame_inline_enabled = true;
20879            self.start_git_blame_inline(user_triggered, window, cx);
20880        }
20881
20882        cx.notify();
20883    }
20884
20885    fn start_git_blame_inline(
20886        &mut self,
20887        user_triggered: bool,
20888        window: &mut Window,
20889        cx: &mut Context<Self>,
20890    ) {
20891        self.start_git_blame(user_triggered, window, cx);
20892
20893        if ProjectSettings::get_global(cx)
20894            .git
20895            .inline_blame_delay()
20896            .is_some()
20897        {
20898            self.start_inline_blame_timer(window, cx);
20899        } else {
20900            self.show_git_blame_inline = true
20901        }
20902    }
20903
20904    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20905        self.blame.as_ref()
20906    }
20907
20908    pub fn show_git_blame_gutter(&self) -> bool {
20909        self.show_git_blame_gutter
20910    }
20911
20912    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20913        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20914    }
20915
20916    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20917        self.show_git_blame_inline
20918            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20919            && !self.newest_selection_head_on_empty_line(cx)
20920            && self.has_blame_entries(cx)
20921    }
20922
20923    fn has_blame_entries(&self, cx: &App) -> bool {
20924        self.blame()
20925            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20926    }
20927
20928    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20929        let cursor_anchor = self.selections.newest_anchor().head();
20930
20931        let snapshot = self.buffer.read(cx).snapshot(cx);
20932        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20933
20934        snapshot.line_len(buffer_row) == 0
20935    }
20936
20937    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20938        let buffer_and_selection = maybe!({
20939            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20940            let selection_range = selection.range();
20941
20942            let multi_buffer = self.buffer().read(cx);
20943            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20944            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20945
20946            let (buffer, range, _) = if selection.reversed {
20947                buffer_ranges.first()
20948            } else {
20949                buffer_ranges.last()
20950            }?;
20951
20952            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
20953            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
20954
20955            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
20956                let selection = start_row_in_buffer..end_row_in_buffer;
20957
20958                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
20959            };
20960
20961            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
20962
20963            Some((
20964                multi_buffer.buffer(buffer.remote_id()).unwrap(),
20965                buffer_diff_snapshot.row_to_base_text_row(start_row_in_buffer, buffer)
20966                    ..buffer_diff_snapshot.row_to_base_text_row(end_row_in_buffer, buffer),
20967            ))
20968        });
20969
20970        let Some((buffer, selection)) = buffer_and_selection else {
20971            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20972        };
20973
20974        let Some(project) = self.project() else {
20975            return Task::ready(Err(anyhow!("editor does not have project")));
20976        };
20977
20978        project.update(cx, |project, cx| {
20979            project.get_permalink_to_line(&buffer, selection, cx)
20980        })
20981    }
20982
20983    pub fn copy_permalink_to_line(
20984        &mut self,
20985        _: &CopyPermalinkToLine,
20986        window: &mut Window,
20987        cx: &mut Context<Self>,
20988    ) {
20989        let permalink_task = self.get_permalink_to_line(cx);
20990        let workspace = self.workspace();
20991
20992        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20993            Ok(permalink) => {
20994                cx.update(|_, cx| {
20995                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20996                })
20997                .ok();
20998            }
20999            Err(err) => {
21000                let message = format!("Failed to copy permalink: {err}");
21001
21002                anyhow::Result::<()>::Err(err).log_err();
21003
21004                if let Some(workspace) = workspace {
21005                    workspace
21006                        .update_in(cx, |workspace, _, cx| {
21007                            struct CopyPermalinkToLine;
21008
21009                            workspace.show_toast(
21010                                Toast::new(
21011                                    NotificationId::unique::<CopyPermalinkToLine>(),
21012                                    message,
21013                                ),
21014                                cx,
21015                            )
21016                        })
21017                        .ok();
21018                }
21019            }
21020        })
21021        .detach();
21022    }
21023
21024    pub fn copy_file_location(
21025        &mut self,
21026        _: &CopyFileLocation,
21027        _: &mut Window,
21028        cx: &mut Context<Self>,
21029    ) {
21030        let selection = self
21031            .selections
21032            .newest::<Point>(&self.display_snapshot(cx))
21033            .start
21034            .row
21035            + 1;
21036        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21037            let project = self.project()?.read(cx);
21038            let file = buffer.read(cx).file()?;
21039            let path = file.path().display(project.path_style(cx));
21040
21041            Some(format!("{path}:{selection}"))
21042        }) {
21043            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
21044        }
21045    }
21046
21047    pub fn open_permalink_to_line(
21048        &mut self,
21049        _: &OpenPermalinkToLine,
21050        window: &mut Window,
21051        cx: &mut Context<Self>,
21052    ) {
21053        let permalink_task = self.get_permalink_to_line(cx);
21054        let workspace = self.workspace();
21055
21056        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21057            Ok(permalink) => {
21058                cx.update(|_, cx| {
21059                    cx.open_url(permalink.as_ref());
21060                })
21061                .ok();
21062            }
21063            Err(err) => {
21064                let message = format!("Failed to open permalink: {err}");
21065
21066                anyhow::Result::<()>::Err(err).log_err();
21067
21068                if let Some(workspace) = workspace {
21069                    workspace
21070                        .update(cx, |workspace, cx| {
21071                            struct OpenPermalinkToLine;
21072
21073                            workspace.show_toast(
21074                                Toast::new(
21075                                    NotificationId::unique::<OpenPermalinkToLine>(),
21076                                    message,
21077                                ),
21078                                cx,
21079                            )
21080                        })
21081                        .ok();
21082                }
21083            }
21084        })
21085        .detach();
21086    }
21087
21088    pub fn insert_uuid_v4(
21089        &mut self,
21090        _: &InsertUuidV4,
21091        window: &mut Window,
21092        cx: &mut Context<Self>,
21093    ) {
21094        self.insert_uuid(UuidVersion::V4, window, cx);
21095    }
21096
21097    pub fn insert_uuid_v7(
21098        &mut self,
21099        _: &InsertUuidV7,
21100        window: &mut Window,
21101        cx: &mut Context<Self>,
21102    ) {
21103        self.insert_uuid(UuidVersion::V7, window, cx);
21104    }
21105
21106    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
21107        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21108        self.transact(window, cx, |this, window, cx| {
21109            let edits = this
21110                .selections
21111                .all::<Point>(&this.display_snapshot(cx))
21112                .into_iter()
21113                .map(|selection| {
21114                    let uuid = match version {
21115                        UuidVersion::V4 => uuid::Uuid::new_v4(),
21116                        UuidVersion::V7 => uuid::Uuid::now_v7(),
21117                    };
21118
21119                    (selection.range(), uuid.to_string())
21120                });
21121            this.edit(edits, cx);
21122            this.refresh_edit_prediction(true, false, window, cx);
21123        });
21124    }
21125
21126    pub fn open_selections_in_multibuffer(
21127        &mut self,
21128        _: &OpenSelectionsInMultibuffer,
21129        window: &mut Window,
21130        cx: &mut Context<Self>,
21131    ) {
21132        let multibuffer = self.buffer.read(cx);
21133
21134        let Some(buffer) = multibuffer.as_singleton() else {
21135            return;
21136        };
21137
21138        let Some(workspace) = self.workspace() else {
21139            return;
21140        };
21141
21142        let title = multibuffer.title(cx).to_string();
21143
21144        let locations = self
21145            .selections
21146            .all_anchors(&self.display_snapshot(cx))
21147            .iter()
21148            .map(|selection| {
21149                (
21150                    buffer.clone(),
21151                    (selection.start.text_anchor..selection.end.text_anchor)
21152                        .to_point(buffer.read(cx)),
21153                )
21154            })
21155            .into_group_map();
21156
21157        cx.spawn_in(window, async move |_, cx| {
21158            workspace.update_in(cx, |workspace, window, cx| {
21159                Self::open_locations_in_multibuffer(
21160                    workspace,
21161                    locations,
21162                    format!("Selections for '{title}'"),
21163                    false,
21164                    false,
21165                    MultibufferSelectionMode::All,
21166                    window,
21167                    cx,
21168                );
21169            })
21170        })
21171        .detach();
21172    }
21173
21174    /// Adds a row highlight for the given range. If a row has multiple highlights, the
21175    /// last highlight added will be used.
21176    ///
21177    /// If the range ends at the beginning of a line, then that line will not be highlighted.
21178    pub fn highlight_rows<T: 'static>(
21179        &mut self,
21180        range: Range<Anchor>,
21181        color: Hsla,
21182        options: RowHighlightOptions,
21183        cx: &mut Context<Self>,
21184    ) {
21185        let snapshot = self.buffer().read(cx).snapshot(cx);
21186        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21187        let ix = row_highlights.binary_search_by(|highlight| {
21188            Ordering::Equal
21189                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
21190                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
21191        });
21192
21193        if let Err(mut ix) = ix {
21194            let index = post_inc(&mut self.highlight_order);
21195
21196            // If this range intersects with the preceding highlight, then merge it with
21197            // the preceding highlight. Otherwise insert a new highlight.
21198            let mut merged = false;
21199            if ix > 0 {
21200                let prev_highlight = &mut row_highlights[ix - 1];
21201                if prev_highlight
21202                    .range
21203                    .end
21204                    .cmp(&range.start, &snapshot)
21205                    .is_ge()
21206                {
21207                    ix -= 1;
21208                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
21209                        prev_highlight.range.end = range.end;
21210                    }
21211                    merged = true;
21212                    prev_highlight.index = index;
21213                    prev_highlight.color = color;
21214                    prev_highlight.options = options;
21215                }
21216            }
21217
21218            if !merged {
21219                row_highlights.insert(
21220                    ix,
21221                    RowHighlight {
21222                        range,
21223                        index,
21224                        color,
21225                        options,
21226                        type_id: TypeId::of::<T>(),
21227                    },
21228                );
21229            }
21230
21231            // If any of the following highlights intersect with this one, merge them.
21232            while let Some(next_highlight) = row_highlights.get(ix + 1) {
21233                let highlight = &row_highlights[ix];
21234                if next_highlight
21235                    .range
21236                    .start
21237                    .cmp(&highlight.range.end, &snapshot)
21238                    .is_le()
21239                {
21240                    if next_highlight
21241                        .range
21242                        .end
21243                        .cmp(&highlight.range.end, &snapshot)
21244                        .is_gt()
21245                    {
21246                        row_highlights[ix].range.end = next_highlight.range.end;
21247                    }
21248                    row_highlights.remove(ix + 1);
21249                } else {
21250                    break;
21251                }
21252            }
21253        }
21254    }
21255
21256    /// Remove any highlighted row ranges of the given type that intersect the
21257    /// given ranges.
21258    pub fn remove_highlighted_rows<T: 'static>(
21259        &mut self,
21260        ranges_to_remove: Vec<Range<Anchor>>,
21261        cx: &mut Context<Self>,
21262    ) {
21263        let snapshot = self.buffer().read(cx).snapshot(cx);
21264        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21265        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21266        row_highlights.retain(|highlight| {
21267            while let Some(range_to_remove) = ranges_to_remove.peek() {
21268                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
21269                    Ordering::Less | Ordering::Equal => {
21270                        ranges_to_remove.next();
21271                    }
21272                    Ordering::Greater => {
21273                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
21274                            Ordering::Less | Ordering::Equal => {
21275                                return false;
21276                            }
21277                            Ordering::Greater => break,
21278                        }
21279                    }
21280                }
21281            }
21282
21283            true
21284        })
21285    }
21286
21287    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
21288    pub fn clear_row_highlights<T: 'static>(&mut self) {
21289        self.highlighted_rows.remove(&TypeId::of::<T>());
21290    }
21291
21292    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
21293    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
21294        self.highlighted_rows
21295            .get(&TypeId::of::<T>())
21296            .map_or(&[] as &[_], |vec| vec.as_slice())
21297            .iter()
21298            .map(|highlight| (highlight.range.clone(), highlight.color))
21299    }
21300
21301    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
21302    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
21303    /// Allows to ignore certain kinds of highlights.
21304    pub fn highlighted_display_rows(
21305        &self,
21306        window: &mut Window,
21307        cx: &mut App,
21308    ) -> BTreeMap<DisplayRow, LineHighlight> {
21309        let snapshot = self.snapshot(window, cx);
21310        let mut used_highlight_orders = HashMap::default();
21311        self.highlighted_rows
21312            .iter()
21313            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
21314            .fold(
21315                BTreeMap::<DisplayRow, LineHighlight>::new(),
21316                |mut unique_rows, highlight| {
21317                    let start = highlight.range.start.to_display_point(&snapshot);
21318                    let end = highlight.range.end.to_display_point(&snapshot);
21319                    let start_row = start.row().0;
21320                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
21321                    {
21322                        end.row().0.saturating_sub(1)
21323                    } else {
21324                        end.row().0
21325                    };
21326                    for row in start_row..=end_row {
21327                        let used_index =
21328                            used_highlight_orders.entry(row).or_insert(highlight.index);
21329                        if highlight.index >= *used_index {
21330                            *used_index = highlight.index;
21331                            unique_rows.insert(
21332                                DisplayRow(row),
21333                                LineHighlight {
21334                                    include_gutter: highlight.options.include_gutter,
21335                                    border: None,
21336                                    background: highlight.color.into(),
21337                                    type_id: Some(highlight.type_id),
21338                                },
21339                            );
21340                        }
21341                    }
21342                    unique_rows
21343                },
21344            )
21345    }
21346
21347    pub fn highlighted_display_row_for_autoscroll(
21348        &self,
21349        snapshot: &DisplaySnapshot,
21350    ) -> Option<DisplayRow> {
21351        self.highlighted_rows
21352            .values()
21353            .flat_map(|highlighted_rows| highlighted_rows.iter())
21354            .filter_map(|highlight| {
21355                if highlight.options.autoscroll {
21356                    Some(highlight.range.start.to_display_point(snapshot).row())
21357                } else {
21358                    None
21359                }
21360            })
21361            .min()
21362    }
21363
21364    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21365        self.highlight_background::<SearchWithinRange>(
21366            ranges,
21367            |_, colors| colors.colors().editor_document_highlight_read_background,
21368            cx,
21369        )
21370    }
21371
21372    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21373        self.breadcrumb_header = Some(new_header);
21374    }
21375
21376    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21377        self.clear_background_highlights::<SearchWithinRange>(cx);
21378    }
21379
21380    pub fn highlight_background<T: 'static>(
21381        &mut self,
21382        ranges: &[Range<Anchor>],
21383        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21384        cx: &mut Context<Self>,
21385    ) {
21386        self.background_highlights.insert(
21387            HighlightKey::Type(TypeId::of::<T>()),
21388            (Arc::new(color_fetcher), Arc::from(ranges)),
21389        );
21390        self.scrollbar_marker_state.dirty = true;
21391        cx.notify();
21392    }
21393
21394    pub fn highlight_background_key<T: 'static>(
21395        &mut self,
21396        key: usize,
21397        ranges: &[Range<Anchor>],
21398        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21399        cx: &mut Context<Self>,
21400    ) {
21401        self.background_highlights.insert(
21402            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21403            (Arc::new(color_fetcher), Arc::from(ranges)),
21404        );
21405        self.scrollbar_marker_state.dirty = true;
21406        cx.notify();
21407    }
21408
21409    pub fn clear_background_highlights<T: 'static>(
21410        &mut self,
21411        cx: &mut Context<Self>,
21412    ) -> Option<BackgroundHighlight> {
21413        let text_highlights = self
21414            .background_highlights
21415            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21416        if !text_highlights.1.is_empty() {
21417            self.scrollbar_marker_state.dirty = true;
21418            cx.notify();
21419        }
21420        Some(text_highlights)
21421    }
21422
21423    pub fn highlight_gutter<T: 'static>(
21424        &mut self,
21425        ranges: impl Into<Vec<Range<Anchor>>>,
21426        color_fetcher: fn(&App) -> Hsla,
21427        cx: &mut Context<Self>,
21428    ) {
21429        self.gutter_highlights
21430            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21431        cx.notify();
21432    }
21433
21434    pub fn clear_gutter_highlights<T: 'static>(
21435        &mut self,
21436        cx: &mut Context<Self>,
21437    ) -> Option<GutterHighlight> {
21438        cx.notify();
21439        self.gutter_highlights.remove(&TypeId::of::<T>())
21440    }
21441
21442    pub fn insert_gutter_highlight<T: 'static>(
21443        &mut self,
21444        range: Range<Anchor>,
21445        color_fetcher: fn(&App) -> Hsla,
21446        cx: &mut Context<Self>,
21447    ) {
21448        let snapshot = self.buffer().read(cx).snapshot(cx);
21449        let mut highlights = self
21450            .gutter_highlights
21451            .remove(&TypeId::of::<T>())
21452            .map(|(_, highlights)| highlights)
21453            .unwrap_or_default();
21454        let ix = highlights.binary_search_by(|highlight| {
21455            Ordering::Equal
21456                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21457                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21458        });
21459        if let Err(ix) = ix {
21460            highlights.insert(ix, range);
21461        }
21462        self.gutter_highlights
21463            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21464    }
21465
21466    pub fn remove_gutter_highlights<T: 'static>(
21467        &mut self,
21468        ranges_to_remove: Vec<Range<Anchor>>,
21469        cx: &mut Context<Self>,
21470    ) {
21471        let snapshot = self.buffer().read(cx).snapshot(cx);
21472        let Some((color_fetcher, mut gutter_highlights)) =
21473            self.gutter_highlights.remove(&TypeId::of::<T>())
21474        else {
21475            return;
21476        };
21477        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21478        gutter_highlights.retain(|highlight| {
21479            while let Some(range_to_remove) = ranges_to_remove.peek() {
21480                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21481                    Ordering::Less | Ordering::Equal => {
21482                        ranges_to_remove.next();
21483                    }
21484                    Ordering::Greater => {
21485                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21486                            Ordering::Less | Ordering::Equal => {
21487                                return false;
21488                            }
21489                            Ordering::Greater => break,
21490                        }
21491                    }
21492                }
21493            }
21494
21495            true
21496        });
21497        self.gutter_highlights
21498            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21499    }
21500
21501    #[cfg(feature = "test-support")]
21502    pub fn all_text_highlights(
21503        &self,
21504        window: &mut Window,
21505        cx: &mut Context<Self>,
21506    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21507        let snapshot = self.snapshot(window, cx);
21508        self.display_map.update(cx, |display_map, _| {
21509            display_map
21510                .all_text_highlights()
21511                .map(|highlight| {
21512                    let (style, ranges) = highlight.as_ref();
21513                    (
21514                        *style,
21515                        ranges
21516                            .iter()
21517                            .map(|range| range.clone().to_display_points(&snapshot))
21518                            .collect(),
21519                    )
21520                })
21521                .collect()
21522        })
21523    }
21524
21525    #[cfg(feature = "test-support")]
21526    pub fn all_text_background_highlights(
21527        &self,
21528        window: &mut Window,
21529        cx: &mut Context<Self>,
21530    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21531        let snapshot = self.snapshot(window, cx);
21532        let buffer = &snapshot.buffer_snapshot();
21533        let start = buffer.anchor_before(MultiBufferOffset(0));
21534        let end = buffer.anchor_after(buffer.len());
21535        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21536    }
21537
21538    #[cfg(any(test, feature = "test-support"))]
21539    pub fn sorted_background_highlights_in_range(
21540        &self,
21541        search_range: Range<Anchor>,
21542        display_snapshot: &DisplaySnapshot,
21543        theme: &Theme,
21544    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21545        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21546        res.sort_by(|a, b| {
21547            a.0.start
21548                .cmp(&b.0.start)
21549                .then_with(|| a.0.end.cmp(&b.0.end))
21550                .then_with(|| a.1.cmp(&b.1))
21551        });
21552        res
21553    }
21554
21555    #[cfg(feature = "test-support")]
21556    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21557        let snapshot = self.buffer().read(cx).snapshot(cx);
21558
21559        let highlights = self
21560            .background_highlights
21561            .get(&HighlightKey::Type(TypeId::of::<
21562                items::BufferSearchHighlights,
21563            >()));
21564
21565        if let Some((_color, ranges)) = highlights {
21566            ranges
21567                .iter()
21568                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21569                .collect_vec()
21570        } else {
21571            vec![]
21572        }
21573    }
21574
21575    fn document_highlights_for_position<'a>(
21576        &'a self,
21577        position: Anchor,
21578        buffer: &'a MultiBufferSnapshot,
21579    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21580        let read_highlights = self
21581            .background_highlights
21582            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21583            .map(|h| &h.1);
21584        let write_highlights = self
21585            .background_highlights
21586            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21587            .map(|h| &h.1);
21588        let left_position = position.bias_left(buffer);
21589        let right_position = position.bias_right(buffer);
21590        read_highlights
21591            .into_iter()
21592            .chain(write_highlights)
21593            .flat_map(move |ranges| {
21594                let start_ix = match ranges.binary_search_by(|probe| {
21595                    let cmp = probe.end.cmp(&left_position, buffer);
21596                    if cmp.is_ge() {
21597                        Ordering::Greater
21598                    } else {
21599                        Ordering::Less
21600                    }
21601                }) {
21602                    Ok(i) | Err(i) => i,
21603                };
21604
21605                ranges[start_ix..]
21606                    .iter()
21607                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21608            })
21609    }
21610
21611    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21612        self.background_highlights
21613            .get(&HighlightKey::Type(TypeId::of::<T>()))
21614            .is_some_and(|(_, highlights)| !highlights.is_empty())
21615    }
21616
21617    /// Returns all background highlights for a given range.
21618    ///
21619    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21620    pub fn background_highlights_in_range(
21621        &self,
21622        search_range: Range<Anchor>,
21623        display_snapshot: &DisplaySnapshot,
21624        theme: &Theme,
21625    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21626        let mut results = Vec::new();
21627        for (color_fetcher, ranges) in self.background_highlights.values() {
21628            let start_ix = match ranges.binary_search_by(|probe| {
21629                let cmp = probe
21630                    .end
21631                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21632                if cmp.is_gt() {
21633                    Ordering::Greater
21634                } else {
21635                    Ordering::Less
21636                }
21637            }) {
21638                Ok(i) | Err(i) => i,
21639            };
21640            for (index, range) in ranges[start_ix..].iter().enumerate() {
21641                if range
21642                    .start
21643                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21644                    .is_ge()
21645                {
21646                    break;
21647                }
21648
21649                let color = color_fetcher(&(start_ix + index), theme);
21650                let start = range.start.to_display_point(display_snapshot);
21651                let end = range.end.to_display_point(display_snapshot);
21652                results.push((start..end, color))
21653            }
21654        }
21655        results
21656    }
21657
21658    pub fn gutter_highlights_in_range(
21659        &self,
21660        search_range: Range<Anchor>,
21661        display_snapshot: &DisplaySnapshot,
21662        cx: &App,
21663    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21664        let mut results = Vec::new();
21665        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21666            let color = color_fetcher(cx);
21667            let start_ix = match ranges.binary_search_by(|probe| {
21668                let cmp = probe
21669                    .end
21670                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21671                if cmp.is_gt() {
21672                    Ordering::Greater
21673                } else {
21674                    Ordering::Less
21675                }
21676            }) {
21677                Ok(i) | Err(i) => i,
21678            };
21679            for range in &ranges[start_ix..] {
21680                if range
21681                    .start
21682                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21683                    .is_ge()
21684                {
21685                    break;
21686                }
21687
21688                let start = range.start.to_display_point(display_snapshot);
21689                let end = range.end.to_display_point(display_snapshot);
21690                results.push((start..end, color))
21691            }
21692        }
21693        results
21694    }
21695
21696    /// Get the text ranges corresponding to the redaction query
21697    pub fn redacted_ranges(
21698        &self,
21699        search_range: Range<Anchor>,
21700        display_snapshot: &DisplaySnapshot,
21701        cx: &App,
21702    ) -> Vec<Range<DisplayPoint>> {
21703        display_snapshot
21704            .buffer_snapshot()
21705            .redacted_ranges(search_range, |file| {
21706                if let Some(file) = file {
21707                    file.is_private()
21708                        && EditorSettings::get(
21709                            Some(SettingsLocation {
21710                                worktree_id: file.worktree_id(cx),
21711                                path: file.path().as_ref(),
21712                            }),
21713                            cx,
21714                        )
21715                        .redact_private_values
21716                } else {
21717                    false
21718                }
21719            })
21720            .map(|range| {
21721                range.start.to_display_point(display_snapshot)
21722                    ..range.end.to_display_point(display_snapshot)
21723            })
21724            .collect()
21725    }
21726
21727    pub fn highlight_text_key<T: 'static>(
21728        &mut self,
21729        key: usize,
21730        ranges: Vec<Range<Anchor>>,
21731        style: HighlightStyle,
21732        merge: bool,
21733        cx: &mut Context<Self>,
21734    ) {
21735        self.display_map.update(cx, |map, cx| {
21736            map.highlight_text(
21737                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21738                ranges,
21739                style,
21740                merge,
21741                cx,
21742            );
21743        });
21744        cx.notify();
21745    }
21746
21747    pub fn highlight_text<T: 'static>(
21748        &mut self,
21749        ranges: Vec<Range<Anchor>>,
21750        style: HighlightStyle,
21751        cx: &mut Context<Self>,
21752    ) {
21753        self.display_map.update(cx, |map, cx| {
21754            map.highlight_text(
21755                HighlightKey::Type(TypeId::of::<T>()),
21756                ranges,
21757                style,
21758                false,
21759                cx,
21760            )
21761        });
21762        cx.notify();
21763    }
21764
21765    pub fn text_highlights<'a, T: 'static>(
21766        &'a self,
21767        cx: &'a App,
21768    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21769        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21770    }
21771
21772    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21773        let cleared = self
21774            .display_map
21775            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21776        if cleared {
21777            cx.notify();
21778        }
21779    }
21780
21781    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21782        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21783            && self.focus_handle.is_focused(window)
21784    }
21785
21786    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21787        self.show_cursor_when_unfocused = is_enabled;
21788        cx.notify();
21789    }
21790
21791    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21792        cx.notify();
21793    }
21794
21795    fn on_debug_session_event(
21796        &mut self,
21797        _session: Entity<Session>,
21798        event: &SessionEvent,
21799        cx: &mut Context<Self>,
21800    ) {
21801        if let SessionEvent::InvalidateInlineValue = event {
21802            self.refresh_inline_values(cx);
21803        }
21804    }
21805
21806    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21807        let Some(project) = self.project.clone() else {
21808            return;
21809        };
21810
21811        if !self.inline_value_cache.enabled {
21812            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21813            self.splice_inlays(&inlays, Vec::new(), cx);
21814            return;
21815        }
21816
21817        let current_execution_position = self
21818            .highlighted_rows
21819            .get(&TypeId::of::<ActiveDebugLine>())
21820            .and_then(|lines| lines.last().map(|line| line.range.end));
21821
21822        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21823            let inline_values = editor
21824                .update(cx, |editor, cx| {
21825                    let Some(current_execution_position) = current_execution_position else {
21826                        return Some(Task::ready(Ok(Vec::new())));
21827                    };
21828
21829                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21830                        let snapshot = buffer.snapshot(cx);
21831
21832                        let excerpt = snapshot.excerpt_containing(
21833                            current_execution_position..current_execution_position,
21834                        )?;
21835
21836                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21837                    })?;
21838
21839                    let range =
21840                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21841
21842                    project.inline_values(buffer, range, cx)
21843                })
21844                .ok()
21845                .flatten()?
21846                .await
21847                .context("refreshing debugger inlays")
21848                .log_err()?;
21849
21850            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21851
21852            for (buffer_id, inline_value) in inline_values
21853                .into_iter()
21854                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21855            {
21856                buffer_inline_values
21857                    .entry(buffer_id)
21858                    .or_default()
21859                    .push(inline_value);
21860            }
21861
21862            editor
21863                .update(cx, |editor, cx| {
21864                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21865                    let mut new_inlays = Vec::default();
21866
21867                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21868                        let buffer_id = buffer_snapshot.remote_id();
21869                        buffer_inline_values
21870                            .get(&buffer_id)
21871                            .into_iter()
21872                            .flatten()
21873                            .for_each(|hint| {
21874                                let inlay = Inlay::debugger(
21875                                    post_inc(&mut editor.next_inlay_id),
21876                                    Anchor::in_buffer(excerpt_id, hint.position),
21877                                    hint.text(),
21878                                );
21879                                if !inlay.text().chars().contains(&'\n') {
21880                                    new_inlays.push(inlay);
21881                                }
21882                            });
21883                    }
21884
21885                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21886                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21887
21888                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21889                })
21890                .ok()?;
21891            Some(())
21892        });
21893    }
21894
21895    fn on_buffer_event(
21896        &mut self,
21897        multibuffer: &Entity<MultiBuffer>,
21898        event: &multi_buffer::Event,
21899        window: &mut Window,
21900        cx: &mut Context<Self>,
21901    ) {
21902        match event {
21903            multi_buffer::Event::Edited { edited_buffer } => {
21904                self.scrollbar_marker_state.dirty = true;
21905                self.active_indent_guides_state.dirty = true;
21906                self.refresh_active_diagnostics(cx);
21907                self.refresh_code_actions(window, cx);
21908                self.refresh_single_line_folds(window, cx);
21909                self.refresh_matching_bracket_highlights(window, cx);
21910                if self.has_active_edit_prediction() {
21911                    self.update_visible_edit_prediction(window, cx);
21912                }
21913
21914                if let Some(buffer) = edited_buffer {
21915                    if buffer.read(cx).file().is_none() {
21916                        cx.emit(EditorEvent::TitleChanged);
21917                    }
21918
21919                    if self.project.is_some() {
21920                        let buffer_id = buffer.read(cx).remote_id();
21921                        self.register_buffer(buffer_id, cx);
21922                        self.update_lsp_data(Some(buffer_id), window, cx);
21923                        self.refresh_inlay_hints(
21924                            InlayHintRefreshReason::BufferEdited(buffer_id),
21925                            cx,
21926                        );
21927                    }
21928                }
21929
21930                cx.emit(EditorEvent::BufferEdited);
21931                cx.emit(SearchEvent::MatchesInvalidated);
21932
21933                let Some(project) = &self.project else { return };
21934                let (telemetry, is_via_ssh) = {
21935                    let project = project.read(cx);
21936                    let telemetry = project.client().telemetry().clone();
21937                    let is_via_ssh = project.is_via_remote_server();
21938                    (telemetry, is_via_ssh)
21939                };
21940                telemetry.log_edit_event("editor", is_via_ssh);
21941            }
21942            multi_buffer::Event::ExcerptsAdded {
21943                buffer,
21944                predecessor,
21945                excerpts,
21946            } => {
21947                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21948                let buffer_id = buffer.read(cx).remote_id();
21949                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21950                    && let Some(project) = &self.project
21951                {
21952                    update_uncommitted_diff_for_buffer(
21953                        cx.entity(),
21954                        project,
21955                        [buffer.clone()],
21956                        self.buffer.clone(),
21957                        cx,
21958                    )
21959                    .detach();
21960                }
21961                self.update_lsp_data(Some(buffer_id), window, cx);
21962                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21963                self.colorize_brackets(false, cx);
21964                cx.emit(EditorEvent::ExcerptsAdded {
21965                    buffer: buffer.clone(),
21966                    predecessor: *predecessor,
21967                    excerpts: excerpts.clone(),
21968                });
21969            }
21970            multi_buffer::Event::ExcerptsRemoved {
21971                ids,
21972                removed_buffer_ids,
21973            } => {
21974                if let Some(inlay_hints) = &mut self.inlay_hints {
21975                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21976                }
21977                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21978                for buffer_id in removed_buffer_ids {
21979                    self.registered_buffers.remove(buffer_id);
21980                }
21981                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21982                cx.emit(EditorEvent::ExcerptsRemoved {
21983                    ids: ids.clone(),
21984                    removed_buffer_ids: removed_buffer_ids.clone(),
21985                });
21986            }
21987            multi_buffer::Event::ExcerptsEdited {
21988                excerpt_ids,
21989                buffer_ids,
21990            } => {
21991                self.display_map.update(cx, |map, cx| {
21992                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21993                });
21994                cx.emit(EditorEvent::ExcerptsEdited {
21995                    ids: excerpt_ids.clone(),
21996                });
21997            }
21998            multi_buffer::Event::ExcerptsExpanded { ids } => {
21999                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22000                self.refresh_document_highlights(cx);
22001                for id in ids {
22002                    self.fetched_tree_sitter_chunks.remove(id);
22003                }
22004                self.colorize_brackets(false, cx);
22005                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
22006            }
22007            multi_buffer::Event::Reparsed(buffer_id) => {
22008                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22009                self.refresh_selected_text_highlights(true, window, cx);
22010                self.colorize_brackets(true, cx);
22011                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22012
22013                cx.emit(EditorEvent::Reparsed(*buffer_id));
22014            }
22015            multi_buffer::Event::DiffHunksToggled => {
22016                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22017            }
22018            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
22019                if !is_fresh_language {
22020                    self.registered_buffers.remove(&buffer_id);
22021                }
22022                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22023                cx.emit(EditorEvent::Reparsed(*buffer_id));
22024                cx.notify();
22025            }
22026            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
22027            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
22028            multi_buffer::Event::FileHandleChanged
22029            | multi_buffer::Event::Reloaded
22030            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
22031            multi_buffer::Event::DiagnosticsUpdated => {
22032                self.update_diagnostics_state(window, cx);
22033            }
22034            _ => {}
22035        };
22036    }
22037
22038    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
22039        if !self.diagnostics_enabled() {
22040            return;
22041        }
22042        self.refresh_active_diagnostics(cx);
22043        self.refresh_inline_diagnostics(true, window, cx);
22044        self.scrollbar_marker_state.dirty = true;
22045        cx.notify();
22046    }
22047
22048    pub fn start_temporary_diff_override(&mut self) {
22049        self.load_diff_task.take();
22050        self.temporary_diff_override = true;
22051    }
22052
22053    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
22054        self.temporary_diff_override = false;
22055        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
22056        self.buffer.update(cx, |buffer, cx| {
22057            buffer.set_all_diff_hunks_collapsed(cx);
22058        });
22059
22060        if let Some(project) = self.project.clone() {
22061            self.load_diff_task = Some(
22062                update_uncommitted_diff_for_buffer(
22063                    cx.entity(),
22064                    &project,
22065                    self.buffer.read(cx).all_buffers(),
22066                    self.buffer.clone(),
22067                    cx,
22068                )
22069                .shared(),
22070            );
22071        }
22072    }
22073
22074    fn on_display_map_changed(
22075        &mut self,
22076        _: Entity<DisplayMap>,
22077        _: &mut Window,
22078        cx: &mut Context<Self>,
22079    ) {
22080        cx.notify();
22081    }
22082
22083    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
22084        if !self.mode.is_full() {
22085            return None;
22086        }
22087
22088        let theme_settings = theme::ThemeSettings::get_global(cx);
22089        let theme = cx.theme();
22090        let accent_colors = theme.accents().clone();
22091
22092        let accent_overrides = theme_settings
22093            .theme_overrides
22094            .get(theme.name.as_ref())
22095            .map(|theme_style| &theme_style.accents)
22096            .into_iter()
22097            .flatten()
22098            .chain(
22099                theme_settings
22100                    .experimental_theme_overrides
22101                    .as_ref()
22102                    .map(|overrides| &overrides.accents)
22103                    .into_iter()
22104                    .flatten(),
22105            )
22106            .flat_map(|accent| accent.0.clone())
22107            .collect();
22108
22109        Some(AccentData {
22110            colors: accent_colors,
22111            overrides: accent_overrides,
22112        })
22113    }
22114
22115    fn fetch_applicable_language_settings(
22116        &self,
22117        cx: &App,
22118    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
22119        if !self.mode.is_full() {
22120            return HashMap::default();
22121        }
22122
22123        self.buffer().read(cx).all_buffers().into_iter().fold(
22124            HashMap::default(),
22125            |mut acc, buffer| {
22126                let buffer = buffer.read(cx);
22127                let language = buffer.language().map(|language| language.name());
22128                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
22129                    let file = buffer.file();
22130                    v.insert(language_settings(language, file, cx).into_owned());
22131                }
22132                acc
22133            },
22134        )
22135    }
22136
22137    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22138        let new_language_settings = self.fetch_applicable_language_settings(cx);
22139        let language_settings_changed = new_language_settings != self.applicable_language_settings;
22140        self.applicable_language_settings = new_language_settings;
22141
22142        let new_accents = self.fetch_accent_data(cx);
22143        let accents_changed = new_accents != self.accent_data;
22144        self.accent_data = new_accents;
22145
22146        if self.diagnostics_enabled() {
22147            let new_severity = EditorSettings::get_global(cx)
22148                .diagnostics_max_severity
22149                .unwrap_or(DiagnosticSeverity::Hint);
22150            self.set_max_diagnostics_severity(new_severity, cx);
22151        }
22152        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22153        self.update_edit_prediction_settings(cx);
22154        self.refresh_edit_prediction(true, false, window, cx);
22155        self.refresh_inline_values(cx);
22156        self.refresh_inlay_hints(
22157            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
22158                self.selections.newest_anchor().head(),
22159                &self.buffer.read(cx).snapshot(cx),
22160                cx,
22161            )),
22162            cx,
22163        );
22164
22165        let old_cursor_shape = self.cursor_shape;
22166        let old_show_breadcrumbs = self.show_breadcrumbs;
22167
22168        {
22169            let editor_settings = EditorSettings::get_global(cx);
22170            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
22171            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
22172            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
22173            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
22174        }
22175
22176        if old_cursor_shape != self.cursor_shape {
22177            cx.emit(EditorEvent::CursorShapeChanged);
22178        }
22179
22180        if old_show_breadcrumbs != self.show_breadcrumbs {
22181            cx.emit(EditorEvent::BreadcrumbsChanged);
22182        }
22183
22184        let project_settings = ProjectSettings::get_global(cx);
22185        self.buffer_serialization = self
22186            .should_serialize_buffer()
22187            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
22188
22189        if self.mode.is_full() {
22190            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
22191            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
22192            if self.show_inline_diagnostics != show_inline_diagnostics {
22193                self.show_inline_diagnostics = show_inline_diagnostics;
22194                self.refresh_inline_diagnostics(false, window, cx);
22195            }
22196
22197            if self.git_blame_inline_enabled != inline_blame_enabled {
22198                self.toggle_git_blame_inline_internal(false, window, cx);
22199            }
22200
22201            let minimap_settings = EditorSettings::get_global(cx).minimap;
22202            if self.minimap_visibility != MinimapVisibility::Disabled {
22203                if self.minimap_visibility.settings_visibility()
22204                    != minimap_settings.minimap_enabled()
22205                {
22206                    self.set_minimap_visibility(
22207                        MinimapVisibility::for_mode(self.mode(), cx),
22208                        window,
22209                        cx,
22210                    );
22211                } else if let Some(minimap_entity) = self.minimap.as_ref() {
22212                    minimap_entity.update(cx, |minimap_editor, cx| {
22213                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
22214                    })
22215                }
22216            }
22217
22218            if language_settings_changed || accents_changed {
22219                self.colorize_brackets(true, cx);
22220            }
22221
22222            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
22223                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
22224            }) {
22225                if !inlay_splice.is_empty() {
22226                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
22227                }
22228                self.refresh_colors_for_visible_range(None, window, cx);
22229            }
22230        }
22231
22232        cx.notify();
22233    }
22234
22235    pub fn set_searchable(&mut self, searchable: bool) {
22236        self.searchable = searchable;
22237    }
22238
22239    pub fn searchable(&self) -> bool {
22240        self.searchable
22241    }
22242
22243    pub fn open_excerpts_in_split(
22244        &mut self,
22245        _: &OpenExcerptsSplit,
22246        window: &mut Window,
22247        cx: &mut Context<Self>,
22248    ) {
22249        self.open_excerpts_common(None, true, window, cx)
22250    }
22251
22252    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
22253        self.open_excerpts_common(None, false, window, cx)
22254    }
22255
22256    fn open_excerpts_common(
22257        &mut self,
22258        jump_data: Option<JumpData>,
22259        split: bool,
22260        window: &mut Window,
22261        cx: &mut Context<Self>,
22262    ) {
22263        let Some(workspace) = self.workspace() else {
22264            cx.propagate();
22265            return;
22266        };
22267
22268        if self.buffer.read(cx).is_singleton() {
22269            cx.propagate();
22270            return;
22271        }
22272
22273        let mut new_selections_by_buffer = HashMap::default();
22274        match &jump_data {
22275            Some(JumpData::MultiBufferPoint {
22276                excerpt_id,
22277                position,
22278                anchor,
22279                line_offset_from_top,
22280            }) => {
22281                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22282                if let Some(buffer) = multi_buffer_snapshot
22283                    .buffer_id_for_excerpt(*excerpt_id)
22284                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
22285                {
22286                    let buffer_snapshot = buffer.read(cx).snapshot();
22287                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
22288                        language::ToPoint::to_point(anchor, &buffer_snapshot)
22289                    } else {
22290                        buffer_snapshot.clip_point(*position, Bias::Left)
22291                    };
22292                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
22293                    new_selections_by_buffer.insert(
22294                        buffer,
22295                        (
22296                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
22297                            Some(*line_offset_from_top),
22298                        ),
22299                    );
22300                }
22301            }
22302            Some(JumpData::MultiBufferRow {
22303                row,
22304                line_offset_from_top,
22305            }) => {
22306                let point = MultiBufferPoint::new(row.0, 0);
22307                if let Some((buffer, buffer_point, _)) =
22308                    self.buffer.read(cx).point_to_buffer_point(point, cx)
22309                {
22310                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
22311                    new_selections_by_buffer
22312                        .entry(buffer)
22313                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
22314                        .0
22315                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
22316                }
22317            }
22318            None => {
22319                let selections = self
22320                    .selections
22321                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
22322                let multi_buffer = self.buffer.read(cx);
22323                for selection in selections {
22324                    for (snapshot, range, _, anchor) in multi_buffer
22325                        .snapshot(cx)
22326                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
22327                    {
22328                        if let Some(anchor) = anchor {
22329                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
22330                            else {
22331                                continue;
22332                            };
22333                            let offset = text::ToOffset::to_offset(
22334                                &anchor.text_anchor,
22335                                &buffer_handle.read(cx).snapshot(),
22336                            );
22337                            let range = BufferOffset(offset)..BufferOffset(offset);
22338                            new_selections_by_buffer
22339                                .entry(buffer_handle)
22340                                .or_insert((Vec::new(), None))
22341                                .0
22342                                .push(range)
22343                        } else {
22344                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22345                            else {
22346                                continue;
22347                            };
22348                            new_selections_by_buffer
22349                                .entry(buffer_handle)
22350                                .or_insert((Vec::new(), None))
22351                                .0
22352                                .push(range)
22353                        }
22354                    }
22355                }
22356            }
22357        }
22358
22359        new_selections_by_buffer
22360            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
22361
22362        if new_selections_by_buffer.is_empty() {
22363            return;
22364        }
22365
22366        // We defer the pane interaction because we ourselves are a workspace item
22367        // and activating a new item causes the pane to call a method on us reentrantly,
22368        // which panics if we're on the stack.
22369        window.defer(cx, move |window, cx| {
22370            workspace.update(cx, |workspace, cx| {
22371                let pane = if split {
22372                    workspace.adjacent_pane(window, cx)
22373                } else {
22374                    workspace.active_pane().clone()
22375                };
22376
22377                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22378                    let buffer_read = buffer.read(cx);
22379                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22380                        (true, project::File::from_dyn(Some(file)).is_some())
22381                    } else {
22382                        (false, false)
22383                    };
22384
22385                    // If project file is none workspace.open_project_item will fail to open the excerpt
22386                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22387                    // so we check if there's a tab match in that case first
22388                    let editor = (!has_file || !is_project_file)
22389                        .then(|| {
22390                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22391                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22392                            // Instead, we try to activate the existing editor in the pane first.
22393                            let (editor, pane_item_index, pane_item_id) =
22394                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22395                                    let editor = item.downcast::<Editor>()?;
22396                                    let singleton_buffer =
22397                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22398                                    if singleton_buffer == buffer {
22399                                        Some((editor, i, item.item_id()))
22400                                    } else {
22401                                        None
22402                                    }
22403                                })?;
22404                            pane.update(cx, |pane, cx| {
22405                                pane.activate_item(pane_item_index, true, true, window, cx);
22406                                if !PreviewTabsSettings::get_global(cx)
22407                                    .enable_preview_from_multibuffer
22408                                {
22409                                    pane.unpreview_item_if_preview(pane_item_id);
22410                                }
22411                            });
22412                            Some(editor)
22413                        })
22414                        .flatten()
22415                        .unwrap_or_else(|| {
22416                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22417                                .enable_keep_preview_on_code_navigation;
22418                            let allow_new_preview =
22419                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22420                            workspace.open_project_item::<Self>(
22421                                pane.clone(),
22422                                buffer,
22423                                true,
22424                                true,
22425                                keep_old_preview,
22426                                allow_new_preview,
22427                                window,
22428                                cx,
22429                            )
22430                        });
22431
22432                    editor.update(cx, |editor, cx| {
22433                        if has_file && !is_project_file {
22434                            editor.set_read_only(true);
22435                        }
22436                        let autoscroll = match scroll_offset {
22437                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22438                            None => Autoscroll::newest(),
22439                        };
22440                        let nav_history = editor.nav_history.take();
22441                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
22442                        let Some((&excerpt_id, _, buffer_snapshot)) =
22443                            multibuffer_snapshot.as_singleton()
22444                        else {
22445                            return;
22446                        };
22447                        editor.change_selections(
22448                            SelectionEffects::scroll(autoscroll),
22449                            window,
22450                            cx,
22451                            |s| {
22452                                s.select_ranges(ranges.into_iter().map(|range| {
22453                                    let range = buffer_snapshot.anchor_before(range.start)
22454                                        ..buffer_snapshot.anchor_after(range.end);
22455                                    multibuffer_snapshot
22456                                        .anchor_range_in_excerpt(excerpt_id, range)
22457                                        .unwrap()
22458                                }));
22459                            },
22460                        );
22461                        editor.nav_history = nav_history;
22462                    });
22463                }
22464            })
22465        });
22466    }
22467
22468    // Allow opening excerpts for buffers that either belong to the current project
22469    // or represent synthetic/non-local files (e.g., git blobs). File-less buffers
22470    // are also supported so tests and other in-memory views keep working.
22471    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
22472        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some() || !file.is_local())
22473    }
22474
22475    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22476        let snapshot = self.buffer.read(cx).read(cx);
22477        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22478        Some(
22479            ranges
22480                .iter()
22481                .map(move |range| {
22482                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22483                })
22484                .collect(),
22485        )
22486    }
22487
22488    fn selection_replacement_ranges(
22489        &self,
22490        range: Range<MultiBufferOffsetUtf16>,
22491        cx: &mut App,
22492    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22493        let selections = self
22494            .selections
22495            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22496        let newest_selection = selections
22497            .iter()
22498            .max_by_key(|selection| selection.id)
22499            .unwrap();
22500        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22501        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22502        let snapshot = self.buffer.read(cx).read(cx);
22503        selections
22504            .into_iter()
22505            .map(|mut selection| {
22506                selection.start.0.0 =
22507                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22508                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22509                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22510                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22511            })
22512            .collect()
22513    }
22514
22515    fn report_editor_event(
22516        &self,
22517        reported_event: ReportEditorEvent,
22518        file_extension: Option<String>,
22519        cx: &App,
22520    ) {
22521        if cfg!(any(test, feature = "test-support")) {
22522            return;
22523        }
22524
22525        let Some(project) = &self.project else { return };
22526
22527        // If None, we are in a file without an extension
22528        let file = self
22529            .buffer
22530            .read(cx)
22531            .as_singleton()
22532            .and_then(|b| b.read(cx).file());
22533        let file_extension = file_extension.or(file
22534            .as_ref()
22535            .and_then(|file| Path::new(file.file_name(cx)).extension())
22536            .and_then(|e| e.to_str())
22537            .map(|a| a.to_string()));
22538
22539        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22540            .map(|vim_mode| vim_mode.0)
22541            .unwrap_or(false);
22542
22543        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22544        let copilot_enabled = edit_predictions_provider
22545            == language::language_settings::EditPredictionProvider::Copilot;
22546        let copilot_enabled_for_language = self
22547            .buffer
22548            .read(cx)
22549            .language_settings(cx)
22550            .show_edit_predictions;
22551
22552        let project = project.read(cx);
22553        let event_type = reported_event.event_type();
22554
22555        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22556            telemetry::event!(
22557                event_type,
22558                type = if auto_saved {"autosave"} else {"manual"},
22559                file_extension,
22560                vim_mode,
22561                copilot_enabled,
22562                copilot_enabled_for_language,
22563                edit_predictions_provider,
22564                is_via_ssh = project.is_via_remote_server(),
22565            );
22566        } else {
22567            telemetry::event!(
22568                event_type,
22569                file_extension,
22570                vim_mode,
22571                copilot_enabled,
22572                copilot_enabled_for_language,
22573                edit_predictions_provider,
22574                is_via_ssh = project.is_via_remote_server(),
22575            );
22576        };
22577    }
22578
22579    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22580    /// with each line being an array of {text, highlight} objects.
22581    fn copy_highlight_json(
22582        &mut self,
22583        _: &CopyHighlightJson,
22584        window: &mut Window,
22585        cx: &mut Context<Self>,
22586    ) {
22587        #[derive(Serialize)]
22588        struct Chunk<'a> {
22589            text: String,
22590            highlight: Option<&'a str>,
22591        }
22592
22593        let snapshot = self.buffer.read(cx).snapshot(cx);
22594        let range = self
22595            .selected_text_range(false, window, cx)
22596            .and_then(|selection| {
22597                if selection.range.is_empty() {
22598                    None
22599                } else {
22600                    Some(
22601                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22602                            selection.range.start,
22603                        )))
22604                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22605                                selection.range.end,
22606                            ))),
22607                    )
22608                }
22609            })
22610            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22611
22612        let chunks = snapshot.chunks(range, true);
22613        let mut lines = Vec::new();
22614        let mut line: VecDeque<Chunk> = VecDeque::new();
22615
22616        let Some(style) = self.style.as_ref() else {
22617            return;
22618        };
22619
22620        for chunk in chunks {
22621            let highlight = chunk
22622                .syntax_highlight_id
22623                .and_then(|id| id.name(&style.syntax));
22624            let mut chunk_lines = chunk.text.split('\n').peekable();
22625            while let Some(text) = chunk_lines.next() {
22626                let mut merged_with_last_token = false;
22627                if let Some(last_token) = line.back_mut()
22628                    && last_token.highlight == highlight
22629                {
22630                    last_token.text.push_str(text);
22631                    merged_with_last_token = true;
22632                }
22633
22634                if !merged_with_last_token {
22635                    line.push_back(Chunk {
22636                        text: text.into(),
22637                        highlight,
22638                    });
22639                }
22640
22641                if chunk_lines.peek().is_some() {
22642                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22643                        line.pop_front();
22644                    }
22645                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22646                        line.pop_back();
22647                    }
22648
22649                    lines.push(mem::take(&mut line));
22650                }
22651            }
22652        }
22653
22654        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22655            return;
22656        };
22657        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22658    }
22659
22660    pub fn open_context_menu(
22661        &mut self,
22662        _: &OpenContextMenu,
22663        window: &mut Window,
22664        cx: &mut Context<Self>,
22665    ) {
22666        self.request_autoscroll(Autoscroll::newest(), cx);
22667        let position = self
22668            .selections
22669            .newest_display(&self.display_snapshot(cx))
22670            .start;
22671        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22672    }
22673
22674    pub fn replay_insert_event(
22675        &mut self,
22676        text: &str,
22677        relative_utf16_range: Option<Range<isize>>,
22678        window: &mut Window,
22679        cx: &mut Context<Self>,
22680    ) {
22681        if !self.input_enabled {
22682            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22683            return;
22684        }
22685        if let Some(relative_utf16_range) = relative_utf16_range {
22686            let selections = self
22687                .selections
22688                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22689            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22690                let new_ranges = selections.into_iter().map(|range| {
22691                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22692                        range
22693                            .head()
22694                            .0
22695                            .0
22696                            .saturating_add_signed(relative_utf16_range.start),
22697                    ));
22698                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22699                        range
22700                            .head()
22701                            .0
22702                            .0
22703                            .saturating_add_signed(relative_utf16_range.end),
22704                    ));
22705                    start..end
22706                });
22707                s.select_ranges(new_ranges);
22708            });
22709        }
22710
22711        self.handle_input(text, window, cx);
22712    }
22713
22714    pub fn is_focused(&self, window: &Window) -> bool {
22715        self.focus_handle.is_focused(window)
22716    }
22717
22718    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22719        cx.emit(EditorEvent::Focused);
22720
22721        if let Some(descendant) = self
22722            .last_focused_descendant
22723            .take()
22724            .and_then(|descendant| descendant.upgrade())
22725        {
22726            window.focus(&descendant);
22727        } else {
22728            if let Some(blame) = self.blame.as_ref() {
22729                blame.update(cx, GitBlame::focus)
22730            }
22731
22732            self.blink_manager.update(cx, BlinkManager::enable);
22733            self.show_cursor_names(window, cx);
22734            self.buffer.update(cx, |buffer, cx| {
22735                buffer.finalize_last_transaction(cx);
22736                if self.leader_id.is_none() {
22737                    buffer.set_active_selections(
22738                        &self.selections.disjoint_anchors_arc(),
22739                        self.selections.line_mode(),
22740                        self.cursor_shape,
22741                        cx,
22742                    );
22743                }
22744            });
22745
22746            if let Some(position_map) = self.last_position_map.clone() {
22747                EditorElement::mouse_moved(
22748                    self,
22749                    &MouseMoveEvent {
22750                        position: window.mouse_position(),
22751                        pressed_button: None,
22752                        modifiers: window.modifiers(),
22753                    },
22754                    &position_map,
22755                    window,
22756                    cx,
22757                );
22758            }
22759        }
22760    }
22761
22762    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22763        cx.emit(EditorEvent::FocusedIn)
22764    }
22765
22766    fn handle_focus_out(
22767        &mut self,
22768        event: FocusOutEvent,
22769        _window: &mut Window,
22770        cx: &mut Context<Self>,
22771    ) {
22772        if event.blurred != self.focus_handle {
22773            self.last_focused_descendant = Some(event.blurred);
22774        }
22775        self.selection_drag_state = SelectionDragState::None;
22776        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22777    }
22778
22779    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22780        self.blink_manager.update(cx, BlinkManager::disable);
22781        self.buffer
22782            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22783
22784        if let Some(blame) = self.blame.as_ref() {
22785            blame.update(cx, GitBlame::blur)
22786        }
22787        if !self.hover_state.focused(window, cx) {
22788            hide_hover(self, cx);
22789        }
22790        if !self
22791            .context_menu
22792            .borrow()
22793            .as_ref()
22794            .is_some_and(|context_menu| context_menu.focused(window, cx))
22795        {
22796            self.hide_context_menu(window, cx);
22797        }
22798        self.take_active_edit_prediction(cx);
22799        cx.emit(EditorEvent::Blurred);
22800        cx.notify();
22801    }
22802
22803    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22804        let mut pending: String = window
22805            .pending_input_keystrokes()
22806            .into_iter()
22807            .flatten()
22808            .filter_map(|keystroke| keystroke.key_char.clone())
22809            .collect();
22810
22811        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22812            pending = "".to_string();
22813        }
22814
22815        let existing_pending = self
22816            .text_highlights::<PendingInput>(cx)
22817            .map(|(_, ranges)| ranges.to_vec());
22818        if existing_pending.is_none() && pending.is_empty() {
22819            return;
22820        }
22821        let transaction =
22822            self.transact(window, cx, |this, window, cx| {
22823                let selections = this
22824                    .selections
22825                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22826                let edits = selections
22827                    .iter()
22828                    .map(|selection| (selection.end..selection.end, pending.clone()));
22829                this.edit(edits, cx);
22830                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22831                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22832                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22833                    }));
22834                });
22835                if let Some(existing_ranges) = existing_pending {
22836                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22837                    this.edit(edits, cx);
22838                }
22839            });
22840
22841        let snapshot = self.snapshot(window, cx);
22842        let ranges = self
22843            .selections
22844            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22845            .into_iter()
22846            .map(|selection| {
22847                snapshot.buffer_snapshot().anchor_after(selection.end)
22848                    ..snapshot
22849                        .buffer_snapshot()
22850                        .anchor_before(selection.end + pending.len())
22851            })
22852            .collect();
22853
22854        if pending.is_empty() {
22855            self.clear_highlights::<PendingInput>(cx);
22856        } else {
22857            self.highlight_text::<PendingInput>(
22858                ranges,
22859                HighlightStyle {
22860                    underline: Some(UnderlineStyle {
22861                        thickness: px(1.),
22862                        color: None,
22863                        wavy: false,
22864                    }),
22865                    ..Default::default()
22866                },
22867                cx,
22868            );
22869        }
22870
22871        self.ime_transaction = self.ime_transaction.or(transaction);
22872        if let Some(transaction) = self.ime_transaction {
22873            self.buffer.update(cx, |buffer, cx| {
22874                buffer.group_until_transaction(transaction, cx);
22875            });
22876        }
22877
22878        if self.text_highlights::<PendingInput>(cx).is_none() {
22879            self.ime_transaction.take();
22880        }
22881    }
22882
22883    pub fn register_action_renderer(
22884        &mut self,
22885        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22886    ) -> Subscription {
22887        let id = self.next_editor_action_id.post_inc();
22888        self.editor_actions
22889            .borrow_mut()
22890            .insert(id, Box::new(listener));
22891
22892        let editor_actions = self.editor_actions.clone();
22893        Subscription::new(move || {
22894            editor_actions.borrow_mut().remove(&id);
22895        })
22896    }
22897
22898    pub fn register_action<A: Action>(
22899        &mut self,
22900        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22901    ) -> Subscription {
22902        let id = self.next_editor_action_id.post_inc();
22903        let listener = Arc::new(listener);
22904        self.editor_actions.borrow_mut().insert(
22905            id,
22906            Box::new(move |_, window, _| {
22907                let listener = listener.clone();
22908                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22909                    let action = action.downcast_ref().unwrap();
22910                    if phase == DispatchPhase::Bubble {
22911                        listener(action, window, cx)
22912                    }
22913                })
22914            }),
22915        );
22916
22917        let editor_actions = self.editor_actions.clone();
22918        Subscription::new(move || {
22919            editor_actions.borrow_mut().remove(&id);
22920        })
22921    }
22922
22923    pub fn file_header_size(&self) -> u32 {
22924        FILE_HEADER_HEIGHT
22925    }
22926
22927    pub fn restore(
22928        &mut self,
22929        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22930        window: &mut Window,
22931        cx: &mut Context<Self>,
22932    ) {
22933        self.buffer().update(cx, |multi_buffer, cx| {
22934            for (buffer_id, changes) in revert_changes {
22935                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22936                    buffer.update(cx, |buffer, cx| {
22937                        buffer.edit(
22938                            changes
22939                                .into_iter()
22940                                .map(|(range, text)| (range, text.to_string())),
22941                            None,
22942                            cx,
22943                        );
22944                    });
22945                }
22946            }
22947        });
22948        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22949            selections.refresh()
22950        });
22951    }
22952
22953    pub fn to_pixel_point(
22954        &mut self,
22955        source: multi_buffer::Anchor,
22956        editor_snapshot: &EditorSnapshot,
22957        window: &mut Window,
22958        cx: &App,
22959    ) -> Option<gpui::Point<Pixels>> {
22960        let source_point = source.to_display_point(editor_snapshot);
22961        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
22962    }
22963
22964    pub fn display_to_pixel_point(
22965        &mut self,
22966        source: DisplayPoint,
22967        editor_snapshot: &EditorSnapshot,
22968        window: &mut Window,
22969        cx: &App,
22970    ) -> Option<gpui::Point<Pixels>> {
22971        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
22972        let text_layout_details = self.text_layout_details(window);
22973        let scroll_top = text_layout_details
22974            .scroll_anchor
22975            .scroll_position(editor_snapshot)
22976            .y;
22977
22978        if source.row().as_f64() < scroll_top.floor() {
22979            return None;
22980        }
22981        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22982        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22983        Some(gpui::Point::new(source_x, source_y))
22984    }
22985
22986    pub fn has_visible_completions_menu(&self) -> bool {
22987        !self.edit_prediction_preview_is_active()
22988            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22989                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22990            })
22991    }
22992
22993    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22994        if self.mode.is_minimap() {
22995            return;
22996        }
22997        self.addons
22998            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22999    }
23000
23001    pub fn unregister_addon<T: Addon>(&mut self) {
23002        self.addons.remove(&std::any::TypeId::of::<T>());
23003    }
23004
23005    pub fn addon<T: Addon>(&self) -> Option<&T> {
23006        let type_id = std::any::TypeId::of::<T>();
23007        self.addons
23008            .get(&type_id)
23009            .and_then(|item| item.to_any().downcast_ref::<T>())
23010    }
23011
23012    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
23013        let type_id = std::any::TypeId::of::<T>();
23014        self.addons
23015            .get_mut(&type_id)
23016            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
23017    }
23018
23019    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
23020        let text_layout_details = self.text_layout_details(window);
23021        let style = &text_layout_details.editor_style;
23022        let font_id = window.text_system().resolve_font(&style.text.font());
23023        let font_size = style.text.font_size.to_pixels(window.rem_size());
23024        let line_height = style.text.line_height_in_pixels(window.rem_size());
23025        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
23026        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
23027
23028        CharacterDimensions {
23029            em_width,
23030            em_advance,
23031            line_height,
23032        }
23033    }
23034
23035    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
23036        self.load_diff_task.clone()
23037    }
23038
23039    fn read_metadata_from_db(
23040        &mut self,
23041        item_id: u64,
23042        workspace_id: WorkspaceId,
23043        window: &mut Window,
23044        cx: &mut Context<Editor>,
23045    ) {
23046        if self.buffer_kind(cx) == ItemBufferKind::Singleton
23047            && !self.mode.is_minimap()
23048            && WorkspaceSettings::get(None, cx).restore_on_startup
23049                != RestoreOnStartupBehavior::EmptyTab
23050        {
23051            let buffer_snapshot = OnceCell::new();
23052
23053            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
23054                && !folds.is_empty()
23055            {
23056                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23057                self.fold_ranges(
23058                    folds
23059                        .into_iter()
23060                        .map(|(start, end)| {
23061                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23062                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23063                        })
23064                        .collect(),
23065                    false,
23066                    window,
23067                    cx,
23068                );
23069            }
23070
23071            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
23072                && !selections.is_empty()
23073            {
23074                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23075                // skip adding the initial selection to selection history
23076                self.selection_history.mode = SelectionHistoryMode::Skipping;
23077                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23078                    s.select_ranges(selections.into_iter().map(|(start, end)| {
23079                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23080                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23081                    }));
23082                });
23083                self.selection_history.mode = SelectionHistoryMode::Normal;
23084            };
23085        }
23086
23087        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
23088    }
23089
23090    fn update_lsp_data(
23091        &mut self,
23092        for_buffer: Option<BufferId>,
23093        window: &mut Window,
23094        cx: &mut Context<'_, Self>,
23095    ) {
23096        self.pull_diagnostics(for_buffer, window, cx);
23097        self.refresh_colors_for_visible_range(for_buffer, window, cx);
23098    }
23099
23100    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
23101        if self.ignore_lsp_data() {
23102            return;
23103        }
23104        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
23105            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
23106        }
23107    }
23108
23109    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
23110        if self.ignore_lsp_data() {
23111            return;
23112        }
23113
23114        if !self.registered_buffers.contains_key(&buffer_id)
23115            && let Some(project) = self.project.as_ref()
23116        {
23117            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
23118                project.update(cx, |project, cx| {
23119                    self.registered_buffers.insert(
23120                        buffer_id,
23121                        project.register_buffer_with_language_servers(&buffer, cx),
23122                    );
23123                });
23124            } else {
23125                self.registered_buffers.remove(&buffer_id);
23126            }
23127        }
23128    }
23129
23130    fn ignore_lsp_data(&self) -> bool {
23131        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
23132        // skip any LSP updates for it.
23133        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
23134    }
23135
23136    fn create_style(&self, cx: &App) -> EditorStyle {
23137        let settings = ThemeSettings::get_global(cx);
23138
23139        let mut text_style = match self.mode {
23140            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23141                color: cx.theme().colors().editor_foreground,
23142                font_family: settings.ui_font.family.clone(),
23143                font_features: settings.ui_font.features.clone(),
23144                font_fallbacks: settings.ui_font.fallbacks.clone(),
23145                font_size: rems(0.875).into(),
23146                font_weight: settings.ui_font.weight,
23147                line_height: relative(settings.buffer_line_height.value()),
23148                ..Default::default()
23149            },
23150            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23151                color: cx.theme().colors().editor_foreground,
23152                font_family: settings.buffer_font.family.clone(),
23153                font_features: settings.buffer_font.features.clone(),
23154                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23155                font_size: settings.buffer_font_size(cx).into(),
23156                font_weight: settings.buffer_font.weight,
23157                line_height: relative(settings.buffer_line_height.value()),
23158                ..Default::default()
23159            },
23160        };
23161        if let Some(text_style_refinement) = &self.text_style_refinement {
23162            text_style.refine(text_style_refinement)
23163        }
23164
23165        let background = match self.mode {
23166            EditorMode::SingleLine => cx.theme().system().transparent,
23167            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23168            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23169            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23170        };
23171
23172        EditorStyle {
23173            background,
23174            border: cx.theme().colors().border,
23175            local_player: cx.theme().players().local(),
23176            text: text_style,
23177            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23178            syntax: cx.theme().syntax().clone(),
23179            status: cx.theme().status().clone(),
23180            inlay_hints_style: make_inlay_hints_style(cx),
23181            edit_prediction_styles: make_suggestion_styles(cx),
23182            unnecessary_code_fade: settings.unnecessary_code_fade,
23183            show_underlines: self.diagnostics_enabled(),
23184        }
23185    }
23186}
23187
23188fn edit_for_markdown_paste<'a>(
23189    buffer: &MultiBufferSnapshot,
23190    range: Range<MultiBufferOffset>,
23191    to_insert: &'a str,
23192    url: Option<url::Url>,
23193) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
23194    if url.is_none() {
23195        return (range, Cow::Borrowed(to_insert));
23196    };
23197
23198    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
23199
23200    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
23201        Cow::Borrowed(to_insert)
23202    } else {
23203        Cow::Owned(format!("[{old_text}]({to_insert})"))
23204    };
23205    (range, new_text)
23206}
23207
23208fn process_completion_for_edit(
23209    completion: &Completion,
23210    intent: CompletionIntent,
23211    buffer: &Entity<Buffer>,
23212    cursor_position: &text::Anchor,
23213    cx: &mut Context<Editor>,
23214) -> CompletionEdit {
23215    let buffer = buffer.read(cx);
23216    let buffer_snapshot = buffer.snapshot();
23217    let (snippet, new_text) = if completion.is_snippet() {
23218        let mut snippet_source = completion.new_text.clone();
23219        // Workaround for typescript language server issues so that methods don't expand within
23220        // strings and functions with type expressions. The previous point is used because the query
23221        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
23222        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
23223        let previous_point = if previous_point.column > 0 {
23224            cursor_position.to_previous_offset(&buffer_snapshot)
23225        } else {
23226            cursor_position.to_offset(&buffer_snapshot)
23227        };
23228        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
23229            && scope.prefers_label_for_snippet_in_completion()
23230            && let Some(label) = completion.label()
23231            && matches!(
23232                completion.kind(),
23233                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
23234            )
23235        {
23236            snippet_source = label;
23237        }
23238        match Snippet::parse(&snippet_source).log_err() {
23239            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
23240            None => (None, completion.new_text.clone()),
23241        }
23242    } else {
23243        (None, completion.new_text.clone())
23244    };
23245
23246    let mut range_to_replace = {
23247        let replace_range = &completion.replace_range;
23248        if let CompletionSource::Lsp {
23249            insert_range: Some(insert_range),
23250            ..
23251        } = &completion.source
23252        {
23253            debug_assert_eq!(
23254                insert_range.start, replace_range.start,
23255                "insert_range and replace_range should start at the same position"
23256            );
23257            debug_assert!(
23258                insert_range
23259                    .start
23260                    .cmp(cursor_position, &buffer_snapshot)
23261                    .is_le(),
23262                "insert_range should start before or at cursor position"
23263            );
23264            debug_assert!(
23265                replace_range
23266                    .start
23267                    .cmp(cursor_position, &buffer_snapshot)
23268                    .is_le(),
23269                "replace_range should start before or at cursor position"
23270            );
23271
23272            let should_replace = match intent {
23273                CompletionIntent::CompleteWithInsert => false,
23274                CompletionIntent::CompleteWithReplace => true,
23275                CompletionIntent::Complete | CompletionIntent::Compose => {
23276                    let insert_mode =
23277                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
23278                            .completions
23279                            .lsp_insert_mode;
23280                    match insert_mode {
23281                        LspInsertMode::Insert => false,
23282                        LspInsertMode::Replace => true,
23283                        LspInsertMode::ReplaceSubsequence => {
23284                            let mut text_to_replace = buffer.chars_for_range(
23285                                buffer.anchor_before(replace_range.start)
23286                                    ..buffer.anchor_after(replace_range.end),
23287                            );
23288                            let mut current_needle = text_to_replace.next();
23289                            for haystack_ch in completion.label.text.chars() {
23290                                if let Some(needle_ch) = current_needle
23291                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
23292                                {
23293                                    current_needle = text_to_replace.next();
23294                                }
23295                            }
23296                            current_needle.is_none()
23297                        }
23298                        LspInsertMode::ReplaceSuffix => {
23299                            if replace_range
23300                                .end
23301                                .cmp(cursor_position, &buffer_snapshot)
23302                                .is_gt()
23303                            {
23304                                let range_after_cursor = *cursor_position..replace_range.end;
23305                                let text_after_cursor = buffer
23306                                    .text_for_range(
23307                                        buffer.anchor_before(range_after_cursor.start)
23308                                            ..buffer.anchor_after(range_after_cursor.end),
23309                                    )
23310                                    .collect::<String>()
23311                                    .to_ascii_lowercase();
23312                                completion
23313                                    .label
23314                                    .text
23315                                    .to_ascii_lowercase()
23316                                    .ends_with(&text_after_cursor)
23317                            } else {
23318                                true
23319                            }
23320                        }
23321                    }
23322                }
23323            };
23324
23325            if should_replace {
23326                replace_range.clone()
23327            } else {
23328                insert_range.clone()
23329            }
23330        } else {
23331            replace_range.clone()
23332        }
23333    };
23334
23335    if range_to_replace
23336        .end
23337        .cmp(cursor_position, &buffer_snapshot)
23338        .is_lt()
23339    {
23340        range_to_replace.end = *cursor_position;
23341    }
23342
23343    let replace_range = range_to_replace.to_offset(buffer);
23344    CompletionEdit {
23345        new_text,
23346        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
23347        snippet,
23348    }
23349}
23350
23351struct CompletionEdit {
23352    new_text: String,
23353    replace_range: Range<BufferOffset>,
23354    snippet: Option<Snippet>,
23355}
23356
23357fn comment_delimiter_for_newline(
23358    start_point: &Point,
23359    buffer: &MultiBufferSnapshot,
23360    language: &LanguageScope,
23361) -> Option<Arc<str>> {
23362    let delimiters = language.line_comment_prefixes();
23363    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
23364    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23365
23366    let num_of_whitespaces = snapshot
23367        .chars_for_range(range.clone())
23368        .take_while(|c| c.is_whitespace())
23369        .count();
23370    let comment_candidate = snapshot
23371        .chars_for_range(range.clone())
23372        .skip(num_of_whitespaces)
23373        .take(max_len_of_delimiter)
23374        .collect::<String>();
23375    let (delimiter, trimmed_len) = delimiters
23376        .iter()
23377        .filter_map(|delimiter| {
23378            let prefix = delimiter.trim_end();
23379            if comment_candidate.starts_with(prefix) {
23380                Some((delimiter, prefix.len()))
23381            } else {
23382                None
23383            }
23384        })
23385        .max_by_key(|(_, len)| *len)?;
23386
23387    if let Some(BlockCommentConfig {
23388        start: block_start, ..
23389    }) = language.block_comment()
23390    {
23391        let block_start_trimmed = block_start.trim_end();
23392        if block_start_trimmed.starts_with(delimiter.trim_end()) {
23393            let line_content = snapshot
23394                .chars_for_range(range)
23395                .skip(num_of_whitespaces)
23396                .take(block_start_trimmed.len())
23397                .collect::<String>();
23398
23399            if line_content.starts_with(block_start_trimmed) {
23400                return None;
23401            }
23402        }
23403    }
23404
23405    let cursor_is_placed_after_comment_marker =
23406        num_of_whitespaces + trimmed_len <= start_point.column as usize;
23407    if cursor_is_placed_after_comment_marker {
23408        Some(delimiter.clone())
23409    } else {
23410        None
23411    }
23412}
23413
23414fn documentation_delimiter_for_newline(
23415    start_point: &Point,
23416    buffer: &MultiBufferSnapshot,
23417    language: &LanguageScope,
23418    newline_formatting: &mut NewlineFormatting,
23419) -> Option<Arc<str>> {
23420    let BlockCommentConfig {
23421        start: start_tag,
23422        end: end_tag,
23423        prefix: delimiter,
23424        tab_size: len,
23425    } = language.documentation_comment()?;
23426    let is_within_block_comment = buffer
23427        .language_scope_at(*start_point)
23428        .is_some_and(|scope| scope.override_name() == Some("comment"));
23429    if !is_within_block_comment {
23430        return None;
23431    }
23432
23433    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23434
23435    let num_of_whitespaces = snapshot
23436        .chars_for_range(range.clone())
23437        .take_while(|c| c.is_whitespace())
23438        .count();
23439
23440    // 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.
23441    let column = start_point.column;
23442    let cursor_is_after_start_tag = {
23443        let start_tag_len = start_tag.len();
23444        let start_tag_line = snapshot
23445            .chars_for_range(range.clone())
23446            .skip(num_of_whitespaces)
23447            .take(start_tag_len)
23448            .collect::<String>();
23449        if start_tag_line.starts_with(start_tag.as_ref()) {
23450            num_of_whitespaces + start_tag_len <= column as usize
23451        } else {
23452            false
23453        }
23454    };
23455
23456    let cursor_is_after_delimiter = {
23457        let delimiter_trim = delimiter.trim_end();
23458        let delimiter_line = snapshot
23459            .chars_for_range(range.clone())
23460            .skip(num_of_whitespaces)
23461            .take(delimiter_trim.len())
23462            .collect::<String>();
23463        if delimiter_line.starts_with(delimiter_trim) {
23464            num_of_whitespaces + delimiter_trim.len() <= column as usize
23465        } else {
23466            false
23467        }
23468    };
23469
23470    let cursor_is_before_end_tag_if_exists = {
23471        let mut char_position = 0u32;
23472        let mut end_tag_offset = None;
23473
23474        'outer: for chunk in snapshot.text_for_range(range) {
23475            if let Some(byte_pos) = chunk.find(&**end_tag) {
23476                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
23477                end_tag_offset = Some(char_position + chars_before_match);
23478                break 'outer;
23479            }
23480            char_position += chunk.chars().count() as u32;
23481        }
23482
23483        if let Some(end_tag_offset) = end_tag_offset {
23484            let cursor_is_before_end_tag = column <= end_tag_offset;
23485            if cursor_is_after_start_tag {
23486                if cursor_is_before_end_tag {
23487                    newline_formatting.insert_extra_newline = true;
23488                }
23489                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
23490                if cursor_is_at_start_of_end_tag {
23491                    newline_formatting.indent_on_extra_newline.len = *len;
23492                }
23493            }
23494            cursor_is_before_end_tag
23495        } else {
23496            true
23497        }
23498    };
23499
23500    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
23501        && cursor_is_before_end_tag_if_exists
23502    {
23503        if cursor_is_after_start_tag {
23504            newline_formatting.indent_on_newline.len = *len;
23505        }
23506        Some(delimiter.clone())
23507    } else {
23508        None
23509    }
23510}
23511
23512#[derive(Debug, Default)]
23513struct NewlineFormatting {
23514    insert_extra_newline: bool,
23515    indent_on_newline: IndentSize,
23516    indent_on_extra_newline: IndentSize,
23517}
23518
23519impl NewlineFormatting {
23520    fn new(
23521        buffer: &MultiBufferSnapshot,
23522        range: Range<MultiBufferOffset>,
23523        language: &LanguageScope,
23524    ) -> Self {
23525        Self {
23526            insert_extra_newline: Self::insert_extra_newline_brackets(
23527                buffer,
23528                range.clone(),
23529                language,
23530            ) || Self::insert_extra_newline_tree_sitter(buffer, range),
23531            indent_on_newline: IndentSize::spaces(0),
23532            indent_on_extra_newline: IndentSize::spaces(0),
23533        }
23534    }
23535
23536    fn insert_extra_newline_brackets(
23537        buffer: &MultiBufferSnapshot,
23538        range: Range<MultiBufferOffset>,
23539        language: &language::LanguageScope,
23540    ) -> bool {
23541        let leading_whitespace_len = buffer
23542            .reversed_chars_at(range.start)
23543            .take_while(|c| c.is_whitespace() && *c != '\n')
23544            .map(|c| c.len_utf8())
23545            .sum::<usize>();
23546        let trailing_whitespace_len = buffer
23547            .chars_at(range.end)
23548            .take_while(|c| c.is_whitespace() && *c != '\n')
23549            .map(|c| c.len_utf8())
23550            .sum::<usize>();
23551        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
23552
23553        language.brackets().any(|(pair, enabled)| {
23554            let pair_start = pair.start.trim_end();
23555            let pair_end = pair.end.trim_start();
23556
23557            enabled
23558                && pair.newline
23559                && buffer.contains_str_at(range.end, pair_end)
23560                && buffer.contains_str_at(
23561                    range.start.saturating_sub_usize(pair_start.len()),
23562                    pair_start,
23563                )
23564        })
23565    }
23566
23567    fn insert_extra_newline_tree_sitter(
23568        buffer: &MultiBufferSnapshot,
23569        range: Range<MultiBufferOffset>,
23570    ) -> bool {
23571        let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
23572            [(buffer, range, _)] => (*buffer, range.clone()),
23573            _ => return false,
23574        };
23575        let pair = {
23576            let mut result: Option<BracketMatch<usize>> = None;
23577
23578            for pair in buffer
23579                .all_bracket_ranges(range.start.0..range.end.0)
23580                .filter(move |pair| {
23581                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
23582                })
23583            {
23584                let len = pair.close_range.end - pair.open_range.start;
23585
23586                if let Some(existing) = &result {
23587                    let existing_len = existing.close_range.end - existing.open_range.start;
23588                    if len > existing_len {
23589                        continue;
23590                    }
23591                }
23592
23593                result = Some(pair);
23594            }
23595
23596            result
23597        };
23598        let Some(pair) = pair else {
23599            return false;
23600        };
23601        pair.newline_only
23602            && buffer
23603                .chars_for_range(pair.open_range.end..range.start.0)
23604                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
23605                .all(|c| c.is_whitespace() && c != '\n')
23606    }
23607}
23608
23609fn update_uncommitted_diff_for_buffer(
23610    editor: Entity<Editor>,
23611    project: &Entity<Project>,
23612    buffers: impl IntoIterator<Item = Entity<Buffer>>,
23613    buffer: Entity<MultiBuffer>,
23614    cx: &mut App,
23615) -> Task<()> {
23616    let mut tasks = Vec::new();
23617    project.update(cx, |project, cx| {
23618        for buffer in buffers {
23619            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
23620                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
23621            }
23622        }
23623    });
23624    cx.spawn(async move |cx| {
23625        let diffs = future::join_all(tasks).await;
23626        if editor
23627            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
23628            .unwrap_or(false)
23629        {
23630            return;
23631        }
23632
23633        buffer
23634            .update(cx, |buffer, cx| {
23635                for diff in diffs.into_iter().flatten() {
23636                    buffer.add_diff(diff, cx);
23637                }
23638            })
23639            .ok();
23640    })
23641}
23642
23643fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
23644    let tab_size = tab_size.get() as usize;
23645    let mut width = offset;
23646
23647    for ch in text.chars() {
23648        width += if ch == '\t' {
23649            tab_size - (width % tab_size)
23650        } else {
23651            1
23652        };
23653    }
23654
23655    width - offset
23656}
23657
23658#[cfg(test)]
23659mod tests {
23660    use super::*;
23661
23662    #[test]
23663    fn test_string_size_with_expanded_tabs() {
23664        let nz = |val| NonZeroU32::new(val).unwrap();
23665        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
23666        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
23667        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
23668        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
23669        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
23670        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
23671        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
23672        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
23673    }
23674}
23675
23676/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
23677struct WordBreakingTokenizer<'a> {
23678    input: &'a str,
23679}
23680
23681impl<'a> WordBreakingTokenizer<'a> {
23682    fn new(input: &'a str) -> Self {
23683        Self { input }
23684    }
23685}
23686
23687fn is_char_ideographic(ch: char) -> bool {
23688    use unicode_script::Script::*;
23689    use unicode_script::UnicodeScript;
23690    matches!(ch.script(), Han | Tangut | Yi)
23691}
23692
23693fn is_grapheme_ideographic(text: &str) -> bool {
23694    text.chars().any(is_char_ideographic)
23695}
23696
23697fn is_grapheme_whitespace(text: &str) -> bool {
23698    text.chars().any(|x| x.is_whitespace())
23699}
23700
23701fn should_stay_with_preceding_ideograph(text: &str) -> bool {
23702    text.chars()
23703        .next()
23704        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
23705}
23706
23707#[derive(PartialEq, Eq, Debug, Clone, Copy)]
23708enum WordBreakToken<'a> {
23709    Word { token: &'a str, grapheme_len: usize },
23710    InlineWhitespace { token: &'a str, grapheme_len: usize },
23711    Newline,
23712}
23713
23714impl<'a> Iterator for WordBreakingTokenizer<'a> {
23715    /// Yields a span, the count of graphemes in the token, and whether it was
23716    /// whitespace. Note that it also breaks at word boundaries.
23717    type Item = WordBreakToken<'a>;
23718
23719    fn next(&mut self) -> Option<Self::Item> {
23720        use unicode_segmentation::UnicodeSegmentation;
23721        if self.input.is_empty() {
23722            return None;
23723        }
23724
23725        let mut iter = self.input.graphemes(true).peekable();
23726        let mut offset = 0;
23727        let mut grapheme_len = 0;
23728        if let Some(first_grapheme) = iter.next() {
23729            let is_newline = first_grapheme == "\n";
23730            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23731            offset += first_grapheme.len();
23732            grapheme_len += 1;
23733            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
23734                if let Some(grapheme) = iter.peek().copied()
23735                    && should_stay_with_preceding_ideograph(grapheme)
23736                {
23737                    offset += grapheme.len();
23738                    grapheme_len += 1;
23739                }
23740            } else {
23741                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23742                let mut next_word_bound = words.peek().copied();
23743                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23744                    next_word_bound = words.next();
23745                }
23746                while let Some(grapheme) = iter.peek().copied() {
23747                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23748                        break;
23749                    };
23750                    if is_grapheme_whitespace(grapheme) != is_whitespace
23751                        || (grapheme == "\n") != is_newline
23752                    {
23753                        break;
23754                    };
23755                    offset += grapheme.len();
23756                    grapheme_len += 1;
23757                    iter.next();
23758                }
23759            }
23760            let token = &self.input[..offset];
23761            self.input = &self.input[offset..];
23762            if token == "\n" {
23763                Some(WordBreakToken::Newline)
23764            } else if is_whitespace {
23765                Some(WordBreakToken::InlineWhitespace {
23766                    token,
23767                    grapheme_len,
23768                })
23769            } else {
23770                Some(WordBreakToken::Word {
23771                    token,
23772                    grapheme_len,
23773                })
23774            }
23775        } else {
23776            None
23777        }
23778    }
23779}
23780
23781#[test]
23782fn test_word_breaking_tokenizer() {
23783    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23784        ("", &[]),
23785        ("  ", &[whitespace("  ", 2)]),
23786        ("Ʒ", &[word("Ʒ", 1)]),
23787        ("Ǽ", &[word("Ǽ", 1)]),
23788        ("", &[word("", 1)]),
23789        ("⋑⋑", &[word("⋑⋑", 2)]),
23790        (
23791            "原理,进而",
23792            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23793        ),
23794        (
23795            "hello world",
23796            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23797        ),
23798        (
23799            "hello, world",
23800            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23801        ),
23802        (
23803            "  hello world",
23804            &[
23805                whitespace("  ", 2),
23806                word("hello", 5),
23807                whitespace(" ", 1),
23808                word("world", 5),
23809            ],
23810        ),
23811        (
23812            "这是什么 \n 钢笔",
23813            &[
23814                word("", 1),
23815                word("", 1),
23816                word("", 1),
23817                word("", 1),
23818                whitespace(" ", 1),
23819                newline(),
23820                whitespace(" ", 1),
23821                word("", 1),
23822                word("", 1),
23823            ],
23824        ),
23825        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23826    ];
23827
23828    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23829        WordBreakToken::Word {
23830            token,
23831            grapheme_len,
23832        }
23833    }
23834
23835    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23836        WordBreakToken::InlineWhitespace {
23837            token,
23838            grapheme_len,
23839        }
23840    }
23841
23842    fn newline() -> WordBreakToken<'static> {
23843        WordBreakToken::Newline
23844    }
23845
23846    for (input, result) in tests {
23847        assert_eq!(
23848            WordBreakingTokenizer::new(input)
23849                .collect::<Vec<_>>()
23850                .as_slice(),
23851            *result,
23852        );
23853    }
23854}
23855
23856fn wrap_with_prefix(
23857    first_line_prefix: String,
23858    subsequent_lines_prefix: String,
23859    unwrapped_text: String,
23860    wrap_column: usize,
23861    tab_size: NonZeroU32,
23862    preserve_existing_whitespace: bool,
23863) -> String {
23864    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23865    let subsequent_lines_prefix_len =
23866        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23867    let mut wrapped_text = String::new();
23868    let mut current_line = first_line_prefix;
23869    let mut is_first_line = true;
23870
23871    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23872    let mut current_line_len = first_line_prefix_len;
23873    let mut in_whitespace = false;
23874    for token in tokenizer {
23875        let have_preceding_whitespace = in_whitespace;
23876        match token {
23877            WordBreakToken::Word {
23878                token,
23879                grapheme_len,
23880            } => {
23881                in_whitespace = false;
23882                let current_prefix_len = if is_first_line {
23883                    first_line_prefix_len
23884                } else {
23885                    subsequent_lines_prefix_len
23886                };
23887                if current_line_len + grapheme_len > wrap_column
23888                    && current_line_len != current_prefix_len
23889                {
23890                    wrapped_text.push_str(current_line.trim_end());
23891                    wrapped_text.push('\n');
23892                    is_first_line = false;
23893                    current_line = subsequent_lines_prefix.clone();
23894                    current_line_len = subsequent_lines_prefix_len;
23895                }
23896                current_line.push_str(token);
23897                current_line_len += grapheme_len;
23898            }
23899            WordBreakToken::InlineWhitespace {
23900                mut token,
23901                mut grapheme_len,
23902            } => {
23903                in_whitespace = true;
23904                if have_preceding_whitespace && !preserve_existing_whitespace {
23905                    continue;
23906                }
23907                if !preserve_existing_whitespace {
23908                    // Keep a single whitespace grapheme as-is
23909                    if let Some(first) =
23910                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23911                    {
23912                        token = first;
23913                    } else {
23914                        token = " ";
23915                    }
23916                    grapheme_len = 1;
23917                }
23918                let current_prefix_len = if is_first_line {
23919                    first_line_prefix_len
23920                } else {
23921                    subsequent_lines_prefix_len
23922                };
23923                if current_line_len + grapheme_len > wrap_column {
23924                    wrapped_text.push_str(current_line.trim_end());
23925                    wrapped_text.push('\n');
23926                    is_first_line = false;
23927                    current_line = subsequent_lines_prefix.clone();
23928                    current_line_len = subsequent_lines_prefix_len;
23929                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23930                    current_line.push_str(token);
23931                    current_line_len += grapheme_len;
23932                }
23933            }
23934            WordBreakToken::Newline => {
23935                in_whitespace = true;
23936                let current_prefix_len = if is_first_line {
23937                    first_line_prefix_len
23938                } else {
23939                    subsequent_lines_prefix_len
23940                };
23941                if preserve_existing_whitespace {
23942                    wrapped_text.push_str(current_line.trim_end());
23943                    wrapped_text.push('\n');
23944                    is_first_line = false;
23945                    current_line = subsequent_lines_prefix.clone();
23946                    current_line_len = subsequent_lines_prefix_len;
23947                } else if have_preceding_whitespace {
23948                    continue;
23949                } else if current_line_len + 1 > wrap_column
23950                    && current_line_len != current_prefix_len
23951                {
23952                    wrapped_text.push_str(current_line.trim_end());
23953                    wrapped_text.push('\n');
23954                    is_first_line = false;
23955                    current_line = subsequent_lines_prefix.clone();
23956                    current_line_len = subsequent_lines_prefix_len;
23957                } else if current_line_len != current_prefix_len {
23958                    current_line.push(' ');
23959                    current_line_len += 1;
23960                }
23961            }
23962        }
23963    }
23964
23965    if !current_line.is_empty() {
23966        wrapped_text.push_str(&current_line);
23967    }
23968    wrapped_text
23969}
23970
23971#[test]
23972fn test_wrap_with_prefix() {
23973    assert_eq!(
23974        wrap_with_prefix(
23975            "# ".to_string(),
23976            "# ".to_string(),
23977            "abcdefg".to_string(),
23978            4,
23979            NonZeroU32::new(4).unwrap(),
23980            false,
23981        ),
23982        "# abcdefg"
23983    );
23984    assert_eq!(
23985        wrap_with_prefix(
23986            "".to_string(),
23987            "".to_string(),
23988            "\thello world".to_string(),
23989            8,
23990            NonZeroU32::new(4).unwrap(),
23991            false,
23992        ),
23993        "hello\nworld"
23994    );
23995    assert_eq!(
23996        wrap_with_prefix(
23997            "// ".to_string(),
23998            "// ".to_string(),
23999            "xx \nyy zz aa bb cc".to_string(),
24000            12,
24001            NonZeroU32::new(4).unwrap(),
24002            false,
24003        ),
24004        "// xx yy zz\n// aa bb cc"
24005    );
24006    assert_eq!(
24007        wrap_with_prefix(
24008            String::new(),
24009            String::new(),
24010            "这是什么 \n 钢笔".to_string(),
24011            3,
24012            NonZeroU32::new(4).unwrap(),
24013            false,
24014        ),
24015        "这是什\n么 钢\n"
24016    );
24017    assert_eq!(
24018        wrap_with_prefix(
24019            String::new(),
24020            String::new(),
24021            format!("foo{}bar", '\u{2009}'), // thin space
24022            80,
24023            NonZeroU32::new(4).unwrap(),
24024            false,
24025        ),
24026        format!("foo{}bar", '\u{2009}')
24027    );
24028}
24029
24030pub trait CollaborationHub {
24031    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
24032    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
24033    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
24034}
24035
24036impl CollaborationHub for Entity<Project> {
24037    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
24038        self.read(cx).collaborators()
24039    }
24040
24041    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
24042        self.read(cx).user_store().read(cx).participant_indices()
24043    }
24044
24045    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
24046        let this = self.read(cx);
24047        let user_ids = this.collaborators().values().map(|c| c.user_id);
24048        this.user_store().read(cx).participant_names(user_ids, cx)
24049    }
24050}
24051
24052pub trait SemanticsProvider {
24053    fn hover(
24054        &self,
24055        buffer: &Entity<Buffer>,
24056        position: text::Anchor,
24057        cx: &mut App,
24058    ) -> Option<Task<Option<Vec<project::Hover>>>>;
24059
24060    fn inline_values(
24061        &self,
24062        buffer_handle: Entity<Buffer>,
24063        range: Range<text::Anchor>,
24064        cx: &mut App,
24065    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
24066
24067    fn applicable_inlay_chunks(
24068        &self,
24069        buffer: &Entity<Buffer>,
24070        ranges: &[Range<text::Anchor>],
24071        cx: &mut App,
24072    ) -> Vec<Range<BufferRow>>;
24073
24074    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
24075
24076    fn inlay_hints(
24077        &self,
24078        invalidate: InvalidationStrategy,
24079        buffer: Entity<Buffer>,
24080        ranges: Vec<Range<text::Anchor>>,
24081        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24082        cx: &mut App,
24083    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
24084
24085    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
24086
24087    fn document_highlights(
24088        &self,
24089        buffer: &Entity<Buffer>,
24090        position: text::Anchor,
24091        cx: &mut App,
24092    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
24093
24094    fn definitions(
24095        &self,
24096        buffer: &Entity<Buffer>,
24097        position: text::Anchor,
24098        kind: GotoDefinitionKind,
24099        cx: &mut App,
24100    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
24101
24102    fn range_for_rename(
24103        &self,
24104        buffer: &Entity<Buffer>,
24105        position: text::Anchor,
24106        cx: &mut App,
24107    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
24108
24109    fn perform_rename(
24110        &self,
24111        buffer: &Entity<Buffer>,
24112        position: text::Anchor,
24113        new_name: String,
24114        cx: &mut App,
24115    ) -> Option<Task<Result<ProjectTransaction>>>;
24116}
24117
24118pub trait CompletionProvider {
24119    fn completions(
24120        &self,
24121        excerpt_id: ExcerptId,
24122        buffer: &Entity<Buffer>,
24123        buffer_position: text::Anchor,
24124        trigger: CompletionContext,
24125        window: &mut Window,
24126        cx: &mut Context<Editor>,
24127    ) -> Task<Result<Vec<CompletionResponse>>>;
24128
24129    fn resolve_completions(
24130        &self,
24131        _buffer: Entity<Buffer>,
24132        _completion_indices: Vec<usize>,
24133        _completions: Rc<RefCell<Box<[Completion]>>>,
24134        _cx: &mut Context<Editor>,
24135    ) -> Task<Result<bool>> {
24136        Task::ready(Ok(false))
24137    }
24138
24139    fn apply_additional_edits_for_completion(
24140        &self,
24141        _buffer: Entity<Buffer>,
24142        _completions: Rc<RefCell<Box<[Completion]>>>,
24143        _completion_index: usize,
24144        _push_to_history: bool,
24145        _cx: &mut Context<Editor>,
24146    ) -> Task<Result<Option<language::Transaction>>> {
24147        Task::ready(Ok(None))
24148    }
24149
24150    fn is_completion_trigger(
24151        &self,
24152        buffer: &Entity<Buffer>,
24153        position: language::Anchor,
24154        text: &str,
24155        trigger_in_words: bool,
24156        cx: &mut Context<Editor>,
24157    ) -> bool;
24158
24159    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
24160
24161    fn sort_completions(&self) -> bool {
24162        true
24163    }
24164
24165    fn filter_completions(&self) -> bool {
24166        true
24167    }
24168
24169    fn show_snippets(&self) -> bool {
24170        false
24171    }
24172}
24173
24174pub trait CodeActionProvider {
24175    fn id(&self) -> Arc<str>;
24176
24177    fn code_actions(
24178        &self,
24179        buffer: &Entity<Buffer>,
24180        range: Range<text::Anchor>,
24181        window: &mut Window,
24182        cx: &mut App,
24183    ) -> Task<Result<Vec<CodeAction>>>;
24184
24185    fn apply_code_action(
24186        &self,
24187        buffer_handle: Entity<Buffer>,
24188        action: CodeAction,
24189        excerpt_id: ExcerptId,
24190        push_to_history: bool,
24191        window: &mut Window,
24192        cx: &mut App,
24193    ) -> Task<Result<ProjectTransaction>>;
24194}
24195
24196impl CodeActionProvider for Entity<Project> {
24197    fn id(&self) -> Arc<str> {
24198        "project".into()
24199    }
24200
24201    fn code_actions(
24202        &self,
24203        buffer: &Entity<Buffer>,
24204        range: Range<text::Anchor>,
24205        _window: &mut Window,
24206        cx: &mut App,
24207    ) -> Task<Result<Vec<CodeAction>>> {
24208        self.update(cx, |project, cx| {
24209            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
24210            let code_actions = project.code_actions(buffer, range, None, cx);
24211            cx.background_spawn(async move {
24212                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
24213                Ok(code_lens_actions
24214                    .context("code lens fetch")?
24215                    .into_iter()
24216                    .flatten()
24217                    .chain(
24218                        code_actions
24219                            .context("code action fetch")?
24220                            .into_iter()
24221                            .flatten(),
24222                    )
24223                    .collect())
24224            })
24225        })
24226    }
24227
24228    fn apply_code_action(
24229        &self,
24230        buffer_handle: Entity<Buffer>,
24231        action: CodeAction,
24232        _excerpt_id: ExcerptId,
24233        push_to_history: bool,
24234        _window: &mut Window,
24235        cx: &mut App,
24236    ) -> Task<Result<ProjectTransaction>> {
24237        self.update(cx, |project, cx| {
24238            project.apply_code_action(buffer_handle, action, push_to_history, cx)
24239        })
24240    }
24241}
24242
24243fn snippet_completions(
24244    project: &Project,
24245    buffer: &Entity<Buffer>,
24246    buffer_anchor: text::Anchor,
24247    classifier: CharClassifier,
24248    cx: &mut App,
24249) -> Task<Result<CompletionResponse>> {
24250    let languages = buffer.read(cx).languages_at(buffer_anchor);
24251    let snippet_store = project.snippets().read(cx);
24252
24253    let scopes: Vec<_> = languages
24254        .iter()
24255        .filter_map(|language| {
24256            let language_name = language.lsp_id();
24257            let snippets = snippet_store.snippets_for(Some(language_name), cx);
24258
24259            if snippets.is_empty() {
24260                None
24261            } else {
24262                Some((language.default_scope(), snippets))
24263            }
24264        })
24265        .collect();
24266
24267    if scopes.is_empty() {
24268        return Task::ready(Ok(CompletionResponse {
24269            completions: vec![],
24270            display_options: CompletionDisplayOptions::default(),
24271            is_incomplete: false,
24272        }));
24273    }
24274
24275    let snapshot = buffer.read(cx).text_snapshot();
24276    let executor = cx.background_executor().clone();
24277
24278    cx.background_spawn(async move {
24279        let is_word_char = |c| classifier.is_word(c);
24280
24281        let mut is_incomplete = false;
24282        let mut completions: Vec<Completion> = Vec::new();
24283
24284        const MAX_PREFIX_LEN: usize = 128;
24285        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
24286        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
24287        let window_start = snapshot.clip_offset(window_start, Bias::Left);
24288
24289        let max_buffer_window: String = snapshot
24290            .text_for_range(window_start..buffer_offset)
24291            .collect();
24292
24293        if max_buffer_window.is_empty() {
24294            return Ok(CompletionResponse {
24295                completions: vec![],
24296                display_options: CompletionDisplayOptions::default(),
24297                is_incomplete: true,
24298            });
24299        }
24300
24301        for (_scope, snippets) in scopes.into_iter() {
24302            // Sort snippets by word count to match longer snippet prefixes first.
24303            let mut sorted_snippet_candidates = snippets
24304                .iter()
24305                .enumerate()
24306                .flat_map(|(snippet_ix, snippet)| {
24307                    snippet
24308                        .prefix
24309                        .iter()
24310                        .enumerate()
24311                        .map(move |(prefix_ix, prefix)| {
24312                            let word_count =
24313                                snippet_candidate_suffixes(prefix, is_word_char).count();
24314                            ((snippet_ix, prefix_ix), prefix, word_count)
24315                        })
24316                })
24317                .collect_vec();
24318            sorted_snippet_candidates
24319                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
24320
24321            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
24322
24323            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
24324                .take(
24325                    sorted_snippet_candidates
24326                        .first()
24327                        .map(|(_, _, word_count)| *word_count)
24328                        .unwrap_or_default(),
24329                )
24330                .collect_vec();
24331
24332            const MAX_RESULTS: usize = 100;
24333            // Each match also remembers how many characters from the buffer it consumed
24334            let mut matches: Vec<(StringMatch, usize)> = vec![];
24335
24336            let mut snippet_list_cutoff_index = 0;
24337            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
24338                let word_count = buffer_index + 1;
24339                // Increase `snippet_list_cutoff_index` until we have all of the
24340                // snippets with sufficiently many words.
24341                while sorted_snippet_candidates
24342                    .get(snippet_list_cutoff_index)
24343                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
24344                        *snippet_word_count >= word_count
24345                    })
24346                {
24347                    snippet_list_cutoff_index += 1;
24348                }
24349
24350                // Take only the candidates with at least `word_count` many words
24351                let snippet_candidates_at_word_len =
24352                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
24353
24354                let candidates = snippet_candidates_at_word_len
24355                    .iter()
24356                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
24357                    .enumerate() // index in `sorted_snippet_candidates`
24358                    // First char must match
24359                    .filter(|(_ix, prefix)| {
24360                        itertools::equal(
24361                            prefix
24362                                .chars()
24363                                .next()
24364                                .into_iter()
24365                                .flat_map(|c| c.to_lowercase()),
24366                            buffer_window
24367                                .chars()
24368                                .next()
24369                                .into_iter()
24370                                .flat_map(|c| c.to_lowercase()),
24371                        )
24372                    })
24373                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
24374                    .collect::<Vec<StringMatchCandidate>>();
24375
24376                matches.extend(
24377                    fuzzy::match_strings(
24378                        &candidates,
24379                        &buffer_window,
24380                        buffer_window.chars().any(|c| c.is_uppercase()),
24381                        true,
24382                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
24383                        &Default::default(),
24384                        executor.clone(),
24385                    )
24386                    .await
24387                    .into_iter()
24388                    .map(|string_match| (string_match, buffer_window.len())),
24389                );
24390
24391                if matches.len() >= MAX_RESULTS {
24392                    break;
24393                }
24394            }
24395
24396            let to_lsp = |point: &text::Anchor| {
24397                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
24398                point_to_lsp(end)
24399            };
24400            let lsp_end = to_lsp(&buffer_anchor);
24401
24402            if matches.len() >= MAX_RESULTS {
24403                is_incomplete = true;
24404            }
24405
24406            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
24407                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
24408                    sorted_snippet_candidates[string_match.candidate_id];
24409                let snippet = &snippets[snippet_index];
24410                let start = buffer_offset - buffer_window_len;
24411                let start = snapshot.anchor_before(start);
24412                let range = start..buffer_anchor;
24413                let lsp_start = to_lsp(&start);
24414                let lsp_range = lsp::Range {
24415                    start: lsp_start,
24416                    end: lsp_end,
24417                };
24418                Completion {
24419                    replace_range: range,
24420                    new_text: snippet.body.clone(),
24421                    source: CompletionSource::Lsp {
24422                        insert_range: None,
24423                        server_id: LanguageServerId(usize::MAX),
24424                        resolved: true,
24425                        lsp_completion: Box::new(lsp::CompletionItem {
24426                            label: snippet.prefix.first().unwrap().clone(),
24427                            kind: Some(CompletionItemKind::SNIPPET),
24428                            label_details: snippet.description.as_ref().map(|description| {
24429                                lsp::CompletionItemLabelDetails {
24430                                    detail: Some(description.clone()),
24431                                    description: None,
24432                                }
24433                            }),
24434                            insert_text_format: Some(InsertTextFormat::SNIPPET),
24435                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
24436                                lsp::InsertReplaceEdit {
24437                                    new_text: snippet.body.clone(),
24438                                    insert: lsp_range,
24439                                    replace: lsp_range,
24440                                },
24441                            )),
24442                            filter_text: Some(snippet.body.clone()),
24443                            sort_text: Some(char::MAX.to_string()),
24444                            ..lsp::CompletionItem::default()
24445                        }),
24446                        lsp_defaults: None,
24447                    },
24448                    label: CodeLabel {
24449                        text: matching_prefix.clone(),
24450                        runs: Vec::new(),
24451                        filter_range: 0..matching_prefix.len(),
24452                    },
24453                    icon_path: None,
24454                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
24455                        single_line: snippet.name.clone().into(),
24456                        plain_text: snippet
24457                            .description
24458                            .clone()
24459                            .map(|description| description.into()),
24460                    }),
24461                    insert_text_mode: None,
24462                    confirm: None,
24463                    match_start: Some(start),
24464                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
24465                }
24466            }));
24467        }
24468
24469        Ok(CompletionResponse {
24470            completions,
24471            display_options: CompletionDisplayOptions::default(),
24472            is_incomplete,
24473        })
24474    })
24475}
24476
24477impl CompletionProvider for Entity<Project> {
24478    fn completions(
24479        &self,
24480        _excerpt_id: ExcerptId,
24481        buffer: &Entity<Buffer>,
24482        buffer_position: text::Anchor,
24483        options: CompletionContext,
24484        _window: &mut Window,
24485        cx: &mut Context<Editor>,
24486    ) -> Task<Result<Vec<CompletionResponse>>> {
24487        self.update(cx, |project, cx| {
24488            let task = project.completions(buffer, buffer_position, options, cx);
24489            cx.background_spawn(task)
24490        })
24491    }
24492
24493    fn resolve_completions(
24494        &self,
24495        buffer: Entity<Buffer>,
24496        completion_indices: Vec<usize>,
24497        completions: Rc<RefCell<Box<[Completion]>>>,
24498        cx: &mut Context<Editor>,
24499    ) -> Task<Result<bool>> {
24500        self.update(cx, |project, cx| {
24501            project.lsp_store().update(cx, |lsp_store, cx| {
24502                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
24503            })
24504        })
24505    }
24506
24507    fn apply_additional_edits_for_completion(
24508        &self,
24509        buffer: Entity<Buffer>,
24510        completions: Rc<RefCell<Box<[Completion]>>>,
24511        completion_index: usize,
24512        push_to_history: bool,
24513        cx: &mut Context<Editor>,
24514    ) -> Task<Result<Option<language::Transaction>>> {
24515        self.update(cx, |project, cx| {
24516            project.lsp_store().update(cx, |lsp_store, cx| {
24517                lsp_store.apply_additional_edits_for_completion(
24518                    buffer,
24519                    completions,
24520                    completion_index,
24521                    push_to_history,
24522                    cx,
24523                )
24524            })
24525        })
24526    }
24527
24528    fn is_completion_trigger(
24529        &self,
24530        buffer: &Entity<Buffer>,
24531        position: language::Anchor,
24532        text: &str,
24533        trigger_in_words: bool,
24534        cx: &mut Context<Editor>,
24535    ) -> bool {
24536        let mut chars = text.chars();
24537        let char = if let Some(char) = chars.next() {
24538            char
24539        } else {
24540            return false;
24541        };
24542        if chars.next().is_some() {
24543            return false;
24544        }
24545
24546        let buffer = buffer.read(cx);
24547        let snapshot = buffer.snapshot();
24548        let classifier = snapshot
24549            .char_classifier_at(position)
24550            .scope_context(Some(CharScopeContext::Completion));
24551        if trigger_in_words && classifier.is_word(char) {
24552            return true;
24553        }
24554
24555        buffer.completion_triggers().contains(text)
24556    }
24557
24558    fn show_snippets(&self) -> bool {
24559        true
24560    }
24561}
24562
24563impl SemanticsProvider for Entity<Project> {
24564    fn hover(
24565        &self,
24566        buffer: &Entity<Buffer>,
24567        position: text::Anchor,
24568        cx: &mut App,
24569    ) -> Option<Task<Option<Vec<project::Hover>>>> {
24570        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
24571    }
24572
24573    fn document_highlights(
24574        &self,
24575        buffer: &Entity<Buffer>,
24576        position: text::Anchor,
24577        cx: &mut App,
24578    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
24579        Some(self.update(cx, |project, cx| {
24580            project.document_highlights(buffer, position, cx)
24581        }))
24582    }
24583
24584    fn definitions(
24585        &self,
24586        buffer: &Entity<Buffer>,
24587        position: text::Anchor,
24588        kind: GotoDefinitionKind,
24589        cx: &mut App,
24590    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
24591        Some(self.update(cx, |project, cx| match kind {
24592            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
24593            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
24594            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
24595            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
24596        }))
24597    }
24598
24599    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
24600        self.update(cx, |project, cx| {
24601            if project
24602                .active_debug_session(cx)
24603                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
24604            {
24605                return true;
24606            }
24607
24608            buffer.update(cx, |buffer, cx| {
24609                project.any_language_server_supports_inlay_hints(buffer, cx)
24610            })
24611        })
24612    }
24613
24614    fn inline_values(
24615        &self,
24616        buffer_handle: Entity<Buffer>,
24617        range: Range<text::Anchor>,
24618        cx: &mut App,
24619    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
24620        self.update(cx, |project, cx| {
24621            let (session, active_stack_frame) = project.active_debug_session(cx)?;
24622
24623            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
24624        })
24625    }
24626
24627    fn applicable_inlay_chunks(
24628        &self,
24629        buffer: &Entity<Buffer>,
24630        ranges: &[Range<text::Anchor>],
24631        cx: &mut App,
24632    ) -> Vec<Range<BufferRow>> {
24633        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24634            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
24635        })
24636    }
24637
24638    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
24639        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
24640            lsp_store.invalidate_inlay_hints(for_buffers)
24641        });
24642    }
24643
24644    fn inlay_hints(
24645        &self,
24646        invalidate: InvalidationStrategy,
24647        buffer: Entity<Buffer>,
24648        ranges: Vec<Range<text::Anchor>>,
24649        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24650        cx: &mut App,
24651    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
24652        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24653            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
24654        }))
24655    }
24656
24657    fn range_for_rename(
24658        &self,
24659        buffer: &Entity<Buffer>,
24660        position: text::Anchor,
24661        cx: &mut App,
24662    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
24663        Some(self.update(cx, |project, cx| {
24664            let buffer = buffer.clone();
24665            let task = project.prepare_rename(buffer.clone(), position, cx);
24666            cx.spawn(async move |_, cx| {
24667                Ok(match task.await? {
24668                    PrepareRenameResponse::Success(range) => Some(range),
24669                    PrepareRenameResponse::InvalidPosition => None,
24670                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
24671                        // Fallback on using TreeSitter info to determine identifier range
24672                        buffer.read_with(cx, |buffer, _| {
24673                            let snapshot = buffer.snapshot();
24674                            let (range, kind) = snapshot.surrounding_word(position, None);
24675                            if kind != Some(CharKind::Word) {
24676                                return None;
24677                            }
24678                            Some(
24679                                snapshot.anchor_before(range.start)
24680                                    ..snapshot.anchor_after(range.end),
24681                            )
24682                        })?
24683                    }
24684                })
24685            })
24686        }))
24687    }
24688
24689    fn perform_rename(
24690        &self,
24691        buffer: &Entity<Buffer>,
24692        position: text::Anchor,
24693        new_name: String,
24694        cx: &mut App,
24695    ) -> Option<Task<Result<ProjectTransaction>>> {
24696        Some(self.update(cx, |project, cx| {
24697            project.perform_rename(buffer.clone(), position, new_name, cx)
24698        }))
24699    }
24700}
24701
24702fn consume_contiguous_rows(
24703    contiguous_row_selections: &mut Vec<Selection<Point>>,
24704    selection: &Selection<Point>,
24705    display_map: &DisplaySnapshot,
24706    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
24707) -> (MultiBufferRow, MultiBufferRow) {
24708    contiguous_row_selections.push(selection.clone());
24709    let start_row = starting_row(selection, display_map);
24710    let mut end_row = ending_row(selection, display_map);
24711
24712    while let Some(next_selection) = selections.peek() {
24713        if next_selection.start.row <= end_row.0 {
24714            end_row = ending_row(next_selection, display_map);
24715            contiguous_row_selections.push(selections.next().unwrap().clone());
24716        } else {
24717            break;
24718        }
24719    }
24720    (start_row, end_row)
24721}
24722
24723fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24724    if selection.start.column > 0 {
24725        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
24726    } else {
24727        MultiBufferRow(selection.start.row)
24728    }
24729}
24730
24731fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24732    if next_selection.end.column > 0 || next_selection.is_empty() {
24733        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
24734    } else {
24735        MultiBufferRow(next_selection.end.row)
24736    }
24737}
24738
24739impl EditorSnapshot {
24740    pub fn remote_selections_in_range<'a>(
24741        &'a self,
24742        range: &'a Range<Anchor>,
24743        collaboration_hub: &dyn CollaborationHub,
24744        cx: &'a App,
24745    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24746        let participant_names = collaboration_hub.user_names(cx);
24747        let participant_indices = collaboration_hub.user_participant_indices(cx);
24748        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24749        let collaborators_by_replica_id = collaborators_by_peer_id
24750            .values()
24751            .map(|collaborator| (collaborator.replica_id, collaborator))
24752            .collect::<HashMap<_, _>>();
24753        self.buffer_snapshot()
24754            .selections_in_range(range, false)
24755            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24756                if replica_id == ReplicaId::AGENT {
24757                    Some(RemoteSelection {
24758                        replica_id,
24759                        selection,
24760                        cursor_shape,
24761                        line_mode,
24762                        collaborator_id: CollaboratorId::Agent,
24763                        user_name: Some("Agent".into()),
24764                        color: cx.theme().players().agent(),
24765                    })
24766                } else {
24767                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24768                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24769                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24770                    Some(RemoteSelection {
24771                        replica_id,
24772                        selection,
24773                        cursor_shape,
24774                        line_mode,
24775                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24776                        user_name,
24777                        color: if let Some(index) = participant_index {
24778                            cx.theme().players().color_for_participant(index.0)
24779                        } else {
24780                            cx.theme().players().absent()
24781                        },
24782                    })
24783                }
24784            })
24785    }
24786
24787    pub fn hunks_for_ranges(
24788        &self,
24789        ranges: impl IntoIterator<Item = Range<Point>>,
24790    ) -> Vec<MultiBufferDiffHunk> {
24791        let mut hunks = Vec::new();
24792        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24793            HashMap::default();
24794        for query_range in ranges {
24795            let query_rows =
24796                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24797            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24798                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24799            ) {
24800                // Include deleted hunks that are adjacent to the query range, because
24801                // otherwise they would be missed.
24802                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24803                if hunk.status().is_deleted() {
24804                    intersects_range |= hunk.row_range.start == query_rows.end;
24805                    intersects_range |= hunk.row_range.end == query_rows.start;
24806                }
24807                if intersects_range {
24808                    if !processed_buffer_rows
24809                        .entry(hunk.buffer_id)
24810                        .or_default()
24811                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24812                    {
24813                        continue;
24814                    }
24815                    hunks.push(hunk);
24816                }
24817            }
24818        }
24819
24820        hunks
24821    }
24822
24823    fn display_diff_hunks_for_rows<'a>(
24824        &'a self,
24825        display_rows: Range<DisplayRow>,
24826        folded_buffers: &'a HashSet<BufferId>,
24827    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24828        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24829        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24830
24831        self.buffer_snapshot()
24832            .diff_hunks_in_range(buffer_start..buffer_end)
24833            .filter_map(|hunk| {
24834                if folded_buffers.contains(&hunk.buffer_id) {
24835                    return None;
24836                }
24837
24838                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24839                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24840
24841                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24842                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24843
24844                let display_hunk = if hunk_display_start.column() != 0 {
24845                    DisplayDiffHunk::Folded {
24846                        display_row: hunk_display_start.row(),
24847                    }
24848                } else {
24849                    let mut end_row = hunk_display_end.row();
24850                    if hunk_display_end.column() > 0 {
24851                        end_row.0 += 1;
24852                    }
24853                    let is_created_file = hunk.is_created_file();
24854
24855                    DisplayDiffHunk::Unfolded {
24856                        status: hunk.status(),
24857                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24858                            ..hunk.diff_base_byte_range.end.0,
24859                        word_diffs: hunk.word_diffs,
24860                        display_row_range: hunk_display_start.row()..end_row,
24861                        multi_buffer_range: Anchor::range_in_buffer(
24862                            hunk.excerpt_id,
24863                            hunk.buffer_range,
24864                        ),
24865                        is_created_file,
24866                    }
24867                };
24868
24869                Some(display_hunk)
24870            })
24871    }
24872
24873    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24874        self.display_snapshot
24875            .buffer_snapshot()
24876            .language_at(position)
24877    }
24878
24879    pub fn is_focused(&self) -> bool {
24880        self.is_focused
24881    }
24882
24883    pub fn placeholder_text(&self) -> Option<String> {
24884        self.placeholder_display_snapshot
24885            .as_ref()
24886            .map(|display_map| display_map.text())
24887    }
24888
24889    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24890        self.scroll_anchor.scroll_position(&self.display_snapshot)
24891    }
24892
24893    pub fn gutter_dimensions(
24894        &self,
24895        font_id: FontId,
24896        font_size: Pixels,
24897        style: &EditorStyle,
24898        window: &mut Window,
24899        cx: &App,
24900    ) -> GutterDimensions {
24901        if self.show_gutter
24902            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
24903            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
24904        {
24905            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24906                matches!(
24907                    ProjectSettings::get_global(cx).git.git_gutter,
24908                    GitGutterSetting::TrackedFiles
24909                )
24910            });
24911            let gutter_settings = EditorSettings::get_global(cx).gutter;
24912            let show_line_numbers = self
24913                .show_line_numbers
24914                .unwrap_or(gutter_settings.line_numbers);
24915            let line_gutter_width = if show_line_numbers {
24916                // Avoid flicker-like gutter resizes when the line number gains another digit by
24917                // only resizing the gutter on files with > 10**min_line_number_digits lines.
24918                let min_width_for_number_on_gutter =
24919                    ch_advance * gutter_settings.min_line_number_digits as f32;
24920                self.max_line_number_width(style, window)
24921                    .max(min_width_for_number_on_gutter)
24922            } else {
24923                0.0.into()
24924            };
24925
24926            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24927            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24928
24929            let git_blame_entries_width =
24930                self.git_blame_gutter_max_author_length
24931                    .map(|max_author_length| {
24932                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24933                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24934
24935                        /// The number of characters to dedicate to gaps and margins.
24936                        const SPACING_WIDTH: usize = 4;
24937
24938                        let max_char_count = max_author_length.min(renderer.max_author_length())
24939                            + ::git::SHORT_SHA_LENGTH
24940                            + MAX_RELATIVE_TIMESTAMP.len()
24941                            + SPACING_WIDTH;
24942
24943                        ch_advance * max_char_count
24944                    });
24945
24946            let is_singleton = self.buffer_snapshot().is_singleton();
24947
24948            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24949            left_padding += if !is_singleton {
24950                ch_width * 4.0
24951            } else if show_runnables || show_breakpoints {
24952                ch_width * 3.0
24953            } else if show_git_gutter && show_line_numbers {
24954                ch_width * 2.0
24955            } else if show_git_gutter || show_line_numbers {
24956                ch_width
24957            } else {
24958                px(0.)
24959            };
24960
24961            let shows_folds = is_singleton && gutter_settings.folds;
24962
24963            let right_padding = if shows_folds && show_line_numbers {
24964                ch_width * 4.0
24965            } else if shows_folds || (!is_singleton && show_line_numbers) {
24966                ch_width * 3.0
24967            } else if show_line_numbers {
24968                ch_width
24969            } else {
24970                px(0.)
24971            };
24972
24973            GutterDimensions {
24974                left_padding,
24975                right_padding,
24976                width: line_gutter_width + left_padding + right_padding,
24977                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24978                git_blame_entries_width,
24979            }
24980        } else if self.offset_content {
24981            GutterDimensions::default_with_margin(font_id, font_size, cx)
24982        } else {
24983            GutterDimensions::default()
24984        }
24985    }
24986
24987    pub fn render_crease_toggle(
24988        &self,
24989        buffer_row: MultiBufferRow,
24990        row_contains_cursor: bool,
24991        editor: Entity<Editor>,
24992        window: &mut Window,
24993        cx: &mut App,
24994    ) -> Option<AnyElement> {
24995        let folded = self.is_line_folded(buffer_row);
24996        let mut is_foldable = false;
24997
24998        if let Some(crease) = self
24999            .crease_snapshot
25000            .query_row(buffer_row, self.buffer_snapshot())
25001        {
25002            is_foldable = true;
25003            match crease {
25004                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
25005                    if let Some(render_toggle) = render_toggle {
25006                        let toggle_callback =
25007                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
25008                                if folded {
25009                                    editor.update(cx, |editor, cx| {
25010                                        editor.fold_at(buffer_row, window, cx)
25011                                    });
25012                                } else {
25013                                    editor.update(cx, |editor, cx| {
25014                                        editor.unfold_at(buffer_row, window, cx)
25015                                    });
25016                                }
25017                            });
25018                        return Some((render_toggle)(
25019                            buffer_row,
25020                            folded,
25021                            toggle_callback,
25022                            window,
25023                            cx,
25024                        ));
25025                    }
25026                }
25027            }
25028        }
25029
25030        is_foldable |= self.starts_indent(buffer_row);
25031
25032        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
25033            Some(
25034                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
25035                    .toggle_state(folded)
25036                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
25037                        if folded {
25038                            this.unfold_at(buffer_row, window, cx);
25039                        } else {
25040                            this.fold_at(buffer_row, window, cx);
25041                        }
25042                    }))
25043                    .into_any_element(),
25044            )
25045        } else {
25046            None
25047        }
25048    }
25049
25050    pub fn render_crease_trailer(
25051        &self,
25052        buffer_row: MultiBufferRow,
25053        window: &mut Window,
25054        cx: &mut App,
25055    ) -> Option<AnyElement> {
25056        let folded = self.is_line_folded(buffer_row);
25057        if let Crease::Inline { render_trailer, .. } = self
25058            .crease_snapshot
25059            .query_row(buffer_row, self.buffer_snapshot())?
25060        {
25061            let render_trailer = render_trailer.as_ref()?;
25062            Some(render_trailer(buffer_row, folded, window, cx))
25063        } else {
25064            None
25065        }
25066    }
25067
25068    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
25069        let digit_count = self.widest_line_number().ilog10() + 1;
25070        column_pixels(style, digit_count as usize, window)
25071    }
25072}
25073
25074pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
25075    let font_size = style.text.font_size.to_pixels(window.rem_size());
25076    let layout = window.text_system().shape_line(
25077        SharedString::from(" ".repeat(column)),
25078        font_size,
25079        &[TextRun {
25080            len: column,
25081            font: style.text.font(),
25082            color: Hsla::default(),
25083            ..Default::default()
25084        }],
25085        None,
25086    );
25087
25088    layout.width
25089}
25090
25091impl Deref for EditorSnapshot {
25092    type Target = DisplaySnapshot;
25093
25094    fn deref(&self) -> &Self::Target {
25095        &self.display_snapshot
25096    }
25097}
25098
25099#[derive(Clone, Debug, PartialEq, Eq)]
25100pub enum EditorEvent {
25101    InputIgnored {
25102        text: Arc<str>,
25103    },
25104    InputHandled {
25105        utf16_range_to_replace: Option<Range<isize>>,
25106        text: Arc<str>,
25107    },
25108    ExcerptsAdded {
25109        buffer: Entity<Buffer>,
25110        predecessor: ExcerptId,
25111        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
25112    },
25113    ExcerptsRemoved {
25114        ids: Vec<ExcerptId>,
25115        removed_buffer_ids: Vec<BufferId>,
25116    },
25117    BufferFoldToggled {
25118        ids: Vec<ExcerptId>,
25119        folded: bool,
25120    },
25121    ExcerptsEdited {
25122        ids: Vec<ExcerptId>,
25123    },
25124    ExcerptsExpanded {
25125        ids: Vec<ExcerptId>,
25126    },
25127    BufferEdited,
25128    Edited {
25129        transaction_id: clock::Lamport,
25130    },
25131    Reparsed(BufferId),
25132    Focused,
25133    FocusedIn,
25134    Blurred,
25135    DirtyChanged,
25136    Saved,
25137    TitleChanged,
25138    SelectionsChanged {
25139        local: bool,
25140    },
25141    ScrollPositionChanged {
25142        local: bool,
25143        autoscroll: bool,
25144    },
25145    TransactionUndone {
25146        transaction_id: clock::Lamport,
25147    },
25148    TransactionBegun {
25149        transaction_id: clock::Lamport,
25150    },
25151    CursorShapeChanged,
25152    BreadcrumbsChanged,
25153    PushedToNavHistory {
25154        anchor: Anchor,
25155        is_deactivate: bool,
25156    },
25157}
25158
25159impl EventEmitter<EditorEvent> for Editor {}
25160
25161impl Focusable for Editor {
25162    fn focus_handle(&self, _cx: &App) -> FocusHandle {
25163        self.focus_handle.clone()
25164    }
25165}
25166
25167impl Render for Editor {
25168    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25169        EditorElement::new(&cx.entity(), self.create_style(cx))
25170    }
25171}
25172
25173impl EntityInputHandler for Editor {
25174    fn text_for_range(
25175        &mut self,
25176        range_utf16: Range<usize>,
25177        adjusted_range: &mut Option<Range<usize>>,
25178        _: &mut Window,
25179        cx: &mut Context<Self>,
25180    ) -> Option<String> {
25181        let snapshot = self.buffer.read(cx).read(cx);
25182        let start = snapshot.clip_offset_utf16(
25183            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
25184            Bias::Left,
25185        );
25186        let end = snapshot.clip_offset_utf16(
25187            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
25188            Bias::Right,
25189        );
25190        if (start.0.0..end.0.0) != range_utf16 {
25191            adjusted_range.replace(start.0.0..end.0.0);
25192        }
25193        Some(snapshot.text_for_range(start..end).collect())
25194    }
25195
25196    fn selected_text_range(
25197        &mut self,
25198        ignore_disabled_input: bool,
25199        _: &mut Window,
25200        cx: &mut Context<Self>,
25201    ) -> Option<UTF16Selection> {
25202        // Prevent the IME menu from appearing when holding down an alphabetic key
25203        // while input is disabled.
25204        if !ignore_disabled_input && !self.input_enabled {
25205            return None;
25206        }
25207
25208        let selection = self
25209            .selections
25210            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25211        let range = selection.range();
25212
25213        Some(UTF16Selection {
25214            range: range.start.0.0..range.end.0.0,
25215            reversed: selection.reversed,
25216        })
25217    }
25218
25219    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
25220        let snapshot = self.buffer.read(cx).read(cx);
25221        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
25222        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
25223    }
25224
25225    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25226        self.clear_highlights::<InputComposition>(cx);
25227        self.ime_transaction.take();
25228    }
25229
25230    fn replace_text_in_range(
25231        &mut self,
25232        range_utf16: Option<Range<usize>>,
25233        text: &str,
25234        window: &mut Window,
25235        cx: &mut Context<Self>,
25236    ) {
25237        if !self.input_enabled {
25238            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25239            return;
25240        }
25241
25242        self.transact(window, cx, |this, window, cx| {
25243            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
25244                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25245                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25246                Some(this.selection_replacement_ranges(range_utf16, cx))
25247            } else {
25248                this.marked_text_ranges(cx)
25249            };
25250
25251            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
25252                let newest_selection_id = this.selections.newest_anchor().id;
25253                this.selections
25254                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25255                    .iter()
25256                    .zip(ranges_to_replace.iter())
25257                    .find_map(|(selection, range)| {
25258                        if selection.id == newest_selection_id {
25259                            Some(
25260                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25261                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25262                            )
25263                        } else {
25264                            None
25265                        }
25266                    })
25267            });
25268
25269            cx.emit(EditorEvent::InputHandled {
25270                utf16_range_to_replace: range_to_replace,
25271                text: text.into(),
25272            });
25273
25274            if let Some(new_selected_ranges) = new_selected_ranges {
25275                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25276                    selections.select_ranges(new_selected_ranges)
25277                });
25278                this.backspace(&Default::default(), window, cx);
25279            }
25280
25281            this.handle_input(text, window, cx);
25282        });
25283
25284        if let Some(transaction) = self.ime_transaction {
25285            self.buffer.update(cx, |buffer, cx| {
25286                buffer.group_until_transaction(transaction, cx);
25287            });
25288        }
25289
25290        self.unmark_text(window, cx);
25291    }
25292
25293    fn replace_and_mark_text_in_range(
25294        &mut self,
25295        range_utf16: Option<Range<usize>>,
25296        text: &str,
25297        new_selected_range_utf16: Option<Range<usize>>,
25298        window: &mut Window,
25299        cx: &mut Context<Self>,
25300    ) {
25301        if !self.input_enabled {
25302            return;
25303        }
25304
25305        let transaction = self.transact(window, cx, |this, window, cx| {
25306            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
25307                let snapshot = this.buffer.read(cx).read(cx);
25308                if let Some(relative_range_utf16) = range_utf16.as_ref() {
25309                    for marked_range in &mut marked_ranges {
25310                        marked_range.end = marked_range.start + relative_range_utf16.end;
25311                        marked_range.start += relative_range_utf16.start;
25312                        marked_range.start =
25313                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
25314                        marked_range.end =
25315                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
25316                    }
25317                }
25318                Some(marked_ranges)
25319            } else if let Some(range_utf16) = range_utf16 {
25320                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25321                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25322                Some(this.selection_replacement_ranges(range_utf16, cx))
25323            } else {
25324                None
25325            };
25326
25327            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
25328                let newest_selection_id = this.selections.newest_anchor().id;
25329                this.selections
25330                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25331                    .iter()
25332                    .zip(ranges_to_replace.iter())
25333                    .find_map(|(selection, range)| {
25334                        if selection.id == newest_selection_id {
25335                            Some(
25336                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25337                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25338                            )
25339                        } else {
25340                            None
25341                        }
25342                    })
25343            });
25344
25345            cx.emit(EditorEvent::InputHandled {
25346                utf16_range_to_replace: range_to_replace,
25347                text: text.into(),
25348            });
25349
25350            if let Some(ranges) = ranges_to_replace {
25351                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25352                    s.select_ranges(ranges)
25353                });
25354            }
25355
25356            let marked_ranges = {
25357                let snapshot = this.buffer.read(cx).read(cx);
25358                this.selections
25359                    .disjoint_anchors_arc()
25360                    .iter()
25361                    .map(|selection| {
25362                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
25363                    })
25364                    .collect::<Vec<_>>()
25365            };
25366
25367            if text.is_empty() {
25368                this.unmark_text(window, cx);
25369            } else {
25370                this.highlight_text::<InputComposition>(
25371                    marked_ranges.clone(),
25372                    HighlightStyle {
25373                        underline: Some(UnderlineStyle {
25374                            thickness: px(1.),
25375                            color: None,
25376                            wavy: false,
25377                        }),
25378                        ..Default::default()
25379                    },
25380                    cx,
25381                );
25382            }
25383
25384            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
25385            let use_autoclose = this.use_autoclose;
25386            let use_auto_surround = this.use_auto_surround;
25387            this.set_use_autoclose(false);
25388            this.set_use_auto_surround(false);
25389            this.handle_input(text, window, cx);
25390            this.set_use_autoclose(use_autoclose);
25391            this.set_use_auto_surround(use_auto_surround);
25392
25393            if let Some(new_selected_range) = new_selected_range_utf16 {
25394                let snapshot = this.buffer.read(cx).read(cx);
25395                let new_selected_ranges = marked_ranges
25396                    .into_iter()
25397                    .map(|marked_range| {
25398                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
25399                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
25400                            insertion_start.0 + new_selected_range.start,
25401                        ));
25402                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
25403                            insertion_start.0 + new_selected_range.end,
25404                        ));
25405                        snapshot.clip_offset_utf16(new_start, Bias::Left)
25406                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
25407                    })
25408                    .collect::<Vec<_>>();
25409
25410                drop(snapshot);
25411                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25412                    selections.select_ranges(new_selected_ranges)
25413                });
25414            }
25415        });
25416
25417        self.ime_transaction = self.ime_transaction.or(transaction);
25418        if let Some(transaction) = self.ime_transaction {
25419            self.buffer.update(cx, |buffer, cx| {
25420                buffer.group_until_transaction(transaction, cx);
25421            });
25422        }
25423
25424        if self.text_highlights::<InputComposition>(cx).is_none() {
25425            self.ime_transaction.take();
25426        }
25427    }
25428
25429    fn bounds_for_range(
25430        &mut self,
25431        range_utf16: Range<usize>,
25432        element_bounds: gpui::Bounds<Pixels>,
25433        window: &mut Window,
25434        cx: &mut Context<Self>,
25435    ) -> Option<gpui::Bounds<Pixels>> {
25436        let text_layout_details = self.text_layout_details(window);
25437        let CharacterDimensions {
25438            em_width,
25439            em_advance,
25440            line_height,
25441        } = self.character_dimensions(window);
25442
25443        let snapshot = self.snapshot(window, cx);
25444        let scroll_position = snapshot.scroll_position();
25445        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
25446
25447        let start =
25448            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
25449        let x = Pixels::from(
25450            ScrollOffset::from(
25451                snapshot.x_for_display_point(start, &text_layout_details)
25452                    + self.gutter_dimensions.full_width(),
25453            ) - scroll_left,
25454        );
25455        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
25456
25457        Some(Bounds {
25458            origin: element_bounds.origin + point(x, y),
25459            size: size(em_width, line_height),
25460        })
25461    }
25462
25463    fn character_index_for_point(
25464        &mut self,
25465        point: gpui::Point<Pixels>,
25466        _window: &mut Window,
25467        _cx: &mut Context<Self>,
25468    ) -> Option<usize> {
25469        let position_map = self.last_position_map.as_ref()?;
25470        if !position_map.text_hitbox.contains(&point) {
25471            return None;
25472        }
25473        let display_point = position_map.point_for_position(point).previous_valid;
25474        let anchor = position_map
25475            .snapshot
25476            .display_point_to_anchor(display_point, Bias::Left);
25477        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
25478        Some(utf16_offset.0.0)
25479    }
25480
25481    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
25482        self.input_enabled
25483    }
25484}
25485
25486trait SelectionExt {
25487    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
25488    fn spanned_rows(
25489        &self,
25490        include_end_if_at_line_start: bool,
25491        map: &DisplaySnapshot,
25492    ) -> Range<MultiBufferRow>;
25493}
25494
25495impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
25496    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
25497        let start = self
25498            .start
25499            .to_point(map.buffer_snapshot())
25500            .to_display_point(map);
25501        let end = self
25502            .end
25503            .to_point(map.buffer_snapshot())
25504            .to_display_point(map);
25505        if self.reversed {
25506            end..start
25507        } else {
25508            start..end
25509        }
25510    }
25511
25512    fn spanned_rows(
25513        &self,
25514        include_end_if_at_line_start: bool,
25515        map: &DisplaySnapshot,
25516    ) -> Range<MultiBufferRow> {
25517        let start = self.start.to_point(map.buffer_snapshot());
25518        let mut end = self.end.to_point(map.buffer_snapshot());
25519        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
25520            end.row -= 1;
25521        }
25522
25523        let buffer_start = map.prev_line_boundary(start).0;
25524        let buffer_end = map.next_line_boundary(end).0;
25525        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
25526    }
25527}
25528
25529impl<T: InvalidationRegion> InvalidationStack<T> {
25530    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
25531    where
25532        S: Clone + ToOffset,
25533    {
25534        while let Some(region) = self.last() {
25535            let all_selections_inside_invalidation_ranges =
25536                if selections.len() == region.ranges().len() {
25537                    selections
25538                        .iter()
25539                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
25540                        .all(|(selection, invalidation_range)| {
25541                            let head = selection.head().to_offset(buffer);
25542                            invalidation_range.start <= head && invalidation_range.end >= head
25543                        })
25544                } else {
25545                    false
25546                };
25547
25548            if all_selections_inside_invalidation_ranges {
25549                break;
25550            } else {
25551                self.pop();
25552            }
25553        }
25554    }
25555}
25556
25557impl<T> Default for InvalidationStack<T> {
25558    fn default() -> Self {
25559        Self(Default::default())
25560    }
25561}
25562
25563impl<T> Deref for InvalidationStack<T> {
25564    type Target = Vec<T>;
25565
25566    fn deref(&self) -> &Self::Target {
25567        &self.0
25568    }
25569}
25570
25571impl<T> DerefMut for InvalidationStack<T> {
25572    fn deref_mut(&mut self) -> &mut Self::Target {
25573        &mut self.0
25574    }
25575}
25576
25577impl InvalidationRegion for SnippetState {
25578    fn ranges(&self) -> &[Range<Anchor>] {
25579        &self.ranges[self.active_index]
25580    }
25581}
25582
25583fn edit_prediction_edit_text(
25584    current_snapshot: &BufferSnapshot,
25585    edits: &[(Range<Anchor>, impl AsRef<str>)],
25586    edit_preview: &EditPreview,
25587    include_deletions: bool,
25588    cx: &App,
25589) -> HighlightedText {
25590    let edits = edits
25591        .iter()
25592        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
25593        .collect::<Vec<_>>();
25594
25595    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
25596}
25597
25598fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
25599    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
25600    // Just show the raw edit text with basic styling
25601    let mut text = String::new();
25602    let mut highlights = Vec::new();
25603
25604    let insertion_highlight_style = HighlightStyle {
25605        color: Some(cx.theme().colors().text),
25606        ..Default::default()
25607    };
25608
25609    for (_, edit_text) in edits {
25610        let start_offset = text.len();
25611        text.push_str(edit_text);
25612        let end_offset = text.len();
25613
25614        if start_offset < end_offset {
25615            highlights.push((start_offset..end_offset, insertion_highlight_style));
25616        }
25617    }
25618
25619    HighlightedText {
25620        text: text.into(),
25621        highlights,
25622    }
25623}
25624
25625pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
25626    match severity {
25627        lsp::DiagnosticSeverity::ERROR => colors.error,
25628        lsp::DiagnosticSeverity::WARNING => colors.warning,
25629        lsp::DiagnosticSeverity::INFORMATION => colors.info,
25630        lsp::DiagnosticSeverity::HINT => colors.info,
25631        _ => colors.ignored,
25632    }
25633}
25634
25635pub fn styled_runs_for_code_label<'a>(
25636    label: &'a CodeLabel,
25637    syntax_theme: &'a theme::SyntaxTheme,
25638    local_player: &'a theme::PlayerColor,
25639) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
25640    let fade_out = HighlightStyle {
25641        fade_out: Some(0.35),
25642        ..Default::default()
25643    };
25644
25645    let mut prev_end = label.filter_range.end;
25646    label
25647        .runs
25648        .iter()
25649        .enumerate()
25650        .flat_map(move |(ix, (range, highlight_id))| {
25651            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
25652                HighlightStyle {
25653                    color: Some(local_player.cursor),
25654                    ..Default::default()
25655                }
25656            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
25657                HighlightStyle {
25658                    background_color: Some(local_player.selection),
25659                    ..Default::default()
25660                }
25661            } else if let Some(style) = highlight_id.style(syntax_theme) {
25662                style
25663            } else {
25664                return Default::default();
25665            };
25666            let muted_style = style.highlight(fade_out);
25667
25668            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
25669            if range.start >= label.filter_range.end {
25670                if range.start > prev_end {
25671                    runs.push((prev_end..range.start, fade_out));
25672                }
25673                runs.push((range.clone(), muted_style));
25674            } else if range.end <= label.filter_range.end {
25675                runs.push((range.clone(), style));
25676            } else {
25677                runs.push((range.start..label.filter_range.end, style));
25678                runs.push((label.filter_range.end..range.end, muted_style));
25679            }
25680            prev_end = cmp::max(prev_end, range.end);
25681
25682            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
25683                runs.push((prev_end..label.text.len(), fade_out));
25684            }
25685
25686            runs
25687        })
25688}
25689
25690pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
25691    let mut prev_index = 0;
25692    let mut prev_codepoint: Option<char> = None;
25693    text.char_indices()
25694        .chain([(text.len(), '\0')])
25695        .filter_map(move |(index, codepoint)| {
25696            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25697            let is_boundary = index == text.len()
25698                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
25699                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
25700            if is_boundary {
25701                let chunk = &text[prev_index..index];
25702                prev_index = index;
25703                Some(chunk)
25704            } else {
25705                None
25706            }
25707        })
25708}
25709
25710/// Given a string of text immediately before the cursor, iterates over possible
25711/// strings a snippet could match to. More precisely: returns an iterator over
25712/// suffixes of `text` created by splitting at word boundaries (before & after
25713/// every non-word character).
25714///
25715/// Shorter suffixes are returned first.
25716pub(crate) fn snippet_candidate_suffixes(
25717    text: &str,
25718    is_word_char: impl Fn(char) -> bool,
25719) -> impl std::iter::Iterator<Item = &str> {
25720    let mut prev_index = text.len();
25721    let mut prev_codepoint = None;
25722    text.char_indices()
25723        .rev()
25724        .chain([(0, '\0')])
25725        .filter_map(move |(index, codepoint)| {
25726            let prev_index = std::mem::replace(&mut prev_index, index);
25727            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25728            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
25729                None
25730            } else {
25731                let chunk = &text[prev_index..]; // go to end of string
25732                Some(chunk)
25733            }
25734        })
25735}
25736
25737pub trait RangeToAnchorExt: Sized {
25738    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25739
25740    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25741        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25742        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25743    }
25744}
25745
25746impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25747    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25748        let start_offset = self.start.to_offset(snapshot);
25749        let end_offset = self.end.to_offset(snapshot);
25750        if start_offset == end_offset {
25751            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25752        } else {
25753            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25754        }
25755    }
25756}
25757
25758pub trait RowExt {
25759    fn as_f64(&self) -> f64;
25760
25761    fn next_row(&self) -> Self;
25762
25763    fn previous_row(&self) -> Self;
25764
25765    fn minus(&self, other: Self) -> u32;
25766}
25767
25768impl RowExt for DisplayRow {
25769    fn as_f64(&self) -> f64 {
25770        self.0 as _
25771    }
25772
25773    fn next_row(&self) -> Self {
25774        Self(self.0 + 1)
25775    }
25776
25777    fn previous_row(&self) -> Self {
25778        Self(self.0.saturating_sub(1))
25779    }
25780
25781    fn minus(&self, other: Self) -> u32 {
25782        self.0 - other.0
25783    }
25784}
25785
25786impl RowExt for MultiBufferRow {
25787    fn as_f64(&self) -> f64 {
25788        self.0 as _
25789    }
25790
25791    fn next_row(&self) -> Self {
25792        Self(self.0 + 1)
25793    }
25794
25795    fn previous_row(&self) -> Self {
25796        Self(self.0.saturating_sub(1))
25797    }
25798
25799    fn minus(&self, other: Self) -> u32 {
25800        self.0 - other.0
25801    }
25802}
25803
25804trait RowRangeExt {
25805    type Row;
25806
25807    fn len(&self) -> usize;
25808
25809    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25810}
25811
25812impl RowRangeExt for Range<MultiBufferRow> {
25813    type Row = MultiBufferRow;
25814
25815    fn len(&self) -> usize {
25816        (self.end.0 - self.start.0) as usize
25817    }
25818
25819    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25820        (self.start.0..self.end.0).map(MultiBufferRow)
25821    }
25822}
25823
25824impl RowRangeExt for Range<DisplayRow> {
25825    type Row = DisplayRow;
25826
25827    fn len(&self) -> usize {
25828        (self.end.0 - self.start.0) as usize
25829    }
25830
25831    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25832        (self.start.0..self.end.0).map(DisplayRow)
25833    }
25834}
25835
25836/// If select range has more than one line, we
25837/// just point the cursor to range.start.
25838fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25839    if range.start.row == range.end.row {
25840        range
25841    } else {
25842        range.start..range.start
25843    }
25844}
25845pub struct KillRing(ClipboardItem);
25846impl Global for KillRing {}
25847
25848const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25849
25850enum BreakpointPromptEditAction {
25851    Log,
25852    Condition,
25853    HitCondition,
25854}
25855
25856struct BreakpointPromptEditor {
25857    pub(crate) prompt: Entity<Editor>,
25858    editor: WeakEntity<Editor>,
25859    breakpoint_anchor: Anchor,
25860    breakpoint: Breakpoint,
25861    edit_action: BreakpointPromptEditAction,
25862    block_ids: HashSet<CustomBlockId>,
25863    editor_margins: Arc<Mutex<EditorMargins>>,
25864    _subscriptions: Vec<Subscription>,
25865}
25866
25867impl BreakpointPromptEditor {
25868    const MAX_LINES: u8 = 4;
25869
25870    fn new(
25871        editor: WeakEntity<Editor>,
25872        breakpoint_anchor: Anchor,
25873        breakpoint: Breakpoint,
25874        edit_action: BreakpointPromptEditAction,
25875        window: &mut Window,
25876        cx: &mut Context<Self>,
25877    ) -> Self {
25878        let base_text = match edit_action {
25879            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25880            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25881            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25882        }
25883        .map(|msg| msg.to_string())
25884        .unwrap_or_default();
25885
25886        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25887        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25888
25889        let prompt = cx.new(|cx| {
25890            let mut prompt = Editor::new(
25891                EditorMode::AutoHeight {
25892                    min_lines: 1,
25893                    max_lines: Some(Self::MAX_LINES as usize),
25894                },
25895                buffer,
25896                None,
25897                window,
25898                cx,
25899            );
25900            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25901            prompt.set_show_cursor_when_unfocused(false, cx);
25902            prompt.set_placeholder_text(
25903                match edit_action {
25904                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25905                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25906                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25907                },
25908                window,
25909                cx,
25910            );
25911
25912            prompt
25913        });
25914
25915        Self {
25916            prompt,
25917            editor,
25918            breakpoint_anchor,
25919            breakpoint,
25920            edit_action,
25921            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25922            block_ids: Default::default(),
25923            _subscriptions: vec![],
25924        }
25925    }
25926
25927    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25928        self.block_ids.extend(block_ids)
25929    }
25930
25931    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25932        if let Some(editor) = self.editor.upgrade() {
25933            let message = self
25934                .prompt
25935                .read(cx)
25936                .buffer
25937                .read(cx)
25938                .as_singleton()
25939                .expect("A multi buffer in breakpoint prompt isn't possible")
25940                .read(cx)
25941                .as_rope()
25942                .to_string();
25943
25944            editor.update(cx, |editor, cx| {
25945                editor.edit_breakpoint_at_anchor(
25946                    self.breakpoint_anchor,
25947                    self.breakpoint.clone(),
25948                    match self.edit_action {
25949                        BreakpointPromptEditAction::Log => {
25950                            BreakpointEditAction::EditLogMessage(message.into())
25951                        }
25952                        BreakpointPromptEditAction::Condition => {
25953                            BreakpointEditAction::EditCondition(message.into())
25954                        }
25955                        BreakpointPromptEditAction::HitCondition => {
25956                            BreakpointEditAction::EditHitCondition(message.into())
25957                        }
25958                    },
25959                    cx,
25960                );
25961
25962                editor.remove_blocks(self.block_ids.clone(), None, cx);
25963                cx.focus_self(window);
25964            });
25965        }
25966    }
25967
25968    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25969        self.editor
25970            .update(cx, |editor, cx| {
25971                editor.remove_blocks(self.block_ids.clone(), None, cx);
25972                window.focus(&editor.focus_handle);
25973            })
25974            .log_err();
25975    }
25976
25977    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25978        let settings = ThemeSettings::get_global(cx);
25979        let text_style = TextStyle {
25980            color: if self.prompt.read(cx).read_only(cx) {
25981                cx.theme().colors().text_disabled
25982            } else {
25983                cx.theme().colors().text
25984            },
25985            font_family: settings.buffer_font.family.clone(),
25986            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25987            font_size: settings.buffer_font_size(cx).into(),
25988            font_weight: settings.buffer_font.weight,
25989            line_height: relative(settings.buffer_line_height.value()),
25990            ..Default::default()
25991        };
25992        EditorElement::new(
25993            &self.prompt,
25994            EditorStyle {
25995                background: cx.theme().colors().editor_background,
25996                local_player: cx.theme().players().local(),
25997                text: text_style,
25998                ..Default::default()
25999            },
26000        )
26001    }
26002}
26003
26004impl Render for BreakpointPromptEditor {
26005    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26006        let editor_margins = *self.editor_margins.lock();
26007        let gutter_dimensions = editor_margins.gutter;
26008        h_flex()
26009            .key_context("Editor")
26010            .bg(cx.theme().colors().editor_background)
26011            .border_y_1()
26012            .border_color(cx.theme().status().info_border)
26013            .size_full()
26014            .py(window.line_height() / 2.5)
26015            .on_action(cx.listener(Self::confirm))
26016            .on_action(cx.listener(Self::cancel))
26017            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
26018            .child(div().flex_1().child(self.render_prompt_editor(cx)))
26019    }
26020}
26021
26022impl Focusable for BreakpointPromptEditor {
26023    fn focus_handle(&self, cx: &App) -> FocusHandle {
26024        self.prompt.focus_handle(cx)
26025    }
26026}
26027
26028fn all_edits_insertions_or_deletions(
26029    edits: &Vec<(Range<Anchor>, Arc<str>)>,
26030    snapshot: &MultiBufferSnapshot,
26031) -> bool {
26032    let mut all_insertions = true;
26033    let mut all_deletions = true;
26034
26035    for (range, new_text) in edits.iter() {
26036        let range_is_empty = range.to_offset(snapshot).is_empty();
26037        let text_is_empty = new_text.is_empty();
26038
26039        if range_is_empty != text_is_empty {
26040            if range_is_empty {
26041                all_deletions = false;
26042            } else {
26043                all_insertions = false;
26044            }
26045        } else {
26046            return false;
26047        }
26048
26049        if !all_insertions && !all_deletions {
26050            return false;
26051        }
26052    }
26053    all_insertions || all_deletions
26054}
26055
26056struct MissingEditPredictionKeybindingTooltip;
26057
26058impl Render for MissingEditPredictionKeybindingTooltip {
26059    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26060        ui::tooltip_container(cx, |container, cx| {
26061            container
26062                .flex_shrink_0()
26063                .max_w_80()
26064                .min_h(rems_from_px(124.))
26065                .justify_between()
26066                .child(
26067                    v_flex()
26068                        .flex_1()
26069                        .text_ui_sm(cx)
26070                        .child(Label::new("Conflict with Accept Keybinding"))
26071                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
26072                )
26073                .child(
26074                    h_flex()
26075                        .pb_1()
26076                        .gap_1()
26077                        .items_end()
26078                        .w_full()
26079                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
26080                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
26081                        }))
26082                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
26083                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
26084                        })),
26085                )
26086        })
26087    }
26088}
26089
26090#[derive(Debug, Clone, Copy, PartialEq)]
26091pub struct LineHighlight {
26092    pub background: Background,
26093    pub border: Option<gpui::Hsla>,
26094    pub include_gutter: bool,
26095    pub type_id: Option<TypeId>,
26096}
26097
26098struct LineManipulationResult {
26099    pub new_text: String,
26100    pub line_count_before: usize,
26101    pub line_count_after: usize,
26102}
26103
26104fn render_diff_hunk_controls(
26105    row: u32,
26106    status: &DiffHunkStatus,
26107    hunk_range: Range<Anchor>,
26108    is_created_file: bool,
26109    line_height: Pixels,
26110    editor: &Entity<Editor>,
26111    _window: &mut Window,
26112    cx: &mut App,
26113) -> AnyElement {
26114    h_flex()
26115        .h(line_height)
26116        .mr_1()
26117        .gap_1()
26118        .px_0p5()
26119        .pb_1()
26120        .border_x_1()
26121        .border_b_1()
26122        .border_color(cx.theme().colors().border_variant)
26123        .rounded_b_lg()
26124        .bg(cx.theme().colors().editor_background)
26125        .gap_1()
26126        .block_mouse_except_scroll()
26127        .shadow_md()
26128        .child(if status.has_secondary_hunk() {
26129            Button::new(("stage", row as u64), "Stage")
26130                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26131                .tooltip({
26132                    let focus_handle = editor.focus_handle(cx);
26133                    move |_window, cx| {
26134                        Tooltip::for_action_in(
26135                            "Stage Hunk",
26136                            &::git::ToggleStaged,
26137                            &focus_handle,
26138                            cx,
26139                        )
26140                    }
26141                })
26142                .on_click({
26143                    let editor = editor.clone();
26144                    move |_event, _window, cx| {
26145                        editor.update(cx, |editor, cx| {
26146                            editor.stage_or_unstage_diff_hunks(
26147                                true,
26148                                vec![hunk_range.start..hunk_range.start],
26149                                cx,
26150                            );
26151                        });
26152                    }
26153                })
26154        } else {
26155            Button::new(("unstage", row as u64), "Unstage")
26156                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26157                .tooltip({
26158                    let focus_handle = editor.focus_handle(cx);
26159                    move |_window, cx| {
26160                        Tooltip::for_action_in(
26161                            "Unstage Hunk",
26162                            &::git::ToggleStaged,
26163                            &focus_handle,
26164                            cx,
26165                        )
26166                    }
26167                })
26168                .on_click({
26169                    let editor = editor.clone();
26170                    move |_event, _window, cx| {
26171                        editor.update(cx, |editor, cx| {
26172                            editor.stage_or_unstage_diff_hunks(
26173                                false,
26174                                vec![hunk_range.start..hunk_range.start],
26175                                cx,
26176                            );
26177                        });
26178                    }
26179                })
26180        })
26181        .child(
26182            Button::new(("restore", row as u64), "Restore")
26183                .tooltip({
26184                    let focus_handle = editor.focus_handle(cx);
26185                    move |_window, cx| {
26186                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
26187                    }
26188                })
26189                .on_click({
26190                    let editor = editor.clone();
26191                    move |_event, window, cx| {
26192                        editor.update(cx, |editor, cx| {
26193                            let snapshot = editor.snapshot(window, cx);
26194                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
26195                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
26196                        });
26197                    }
26198                })
26199                .disabled(is_created_file),
26200        )
26201        .when(
26202            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
26203            |el| {
26204                el.child(
26205                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
26206                        .shape(IconButtonShape::Square)
26207                        .icon_size(IconSize::Small)
26208                        // .disabled(!has_multiple_hunks)
26209                        .tooltip({
26210                            let focus_handle = editor.focus_handle(cx);
26211                            move |_window, cx| {
26212                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
26213                            }
26214                        })
26215                        .on_click({
26216                            let editor = editor.clone();
26217                            move |_event, window, cx| {
26218                                editor.update(cx, |editor, cx| {
26219                                    let snapshot = editor.snapshot(window, cx);
26220                                    let position =
26221                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
26222                                    editor.go_to_hunk_before_or_after_position(
26223                                        &snapshot,
26224                                        position,
26225                                        Direction::Next,
26226                                        window,
26227                                        cx,
26228                                    );
26229                                    editor.expand_selected_diff_hunks(cx);
26230                                });
26231                            }
26232                        }),
26233                )
26234                .child(
26235                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
26236                        .shape(IconButtonShape::Square)
26237                        .icon_size(IconSize::Small)
26238                        // .disabled(!has_multiple_hunks)
26239                        .tooltip({
26240                            let focus_handle = editor.focus_handle(cx);
26241                            move |_window, cx| {
26242                                Tooltip::for_action_in(
26243                                    "Previous Hunk",
26244                                    &GoToPreviousHunk,
26245                                    &focus_handle,
26246                                    cx,
26247                                )
26248                            }
26249                        })
26250                        .on_click({
26251                            let editor = editor.clone();
26252                            move |_event, window, cx| {
26253                                editor.update(cx, |editor, cx| {
26254                                    let snapshot = editor.snapshot(window, cx);
26255                                    let point =
26256                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
26257                                    editor.go_to_hunk_before_or_after_position(
26258                                        &snapshot,
26259                                        point,
26260                                        Direction::Prev,
26261                                        window,
26262                                        cx,
26263                                    );
26264                                    editor.expand_selected_diff_hunks(cx);
26265                                });
26266                            }
26267                        }),
26268                )
26269            },
26270        )
26271        .into_any_element()
26272}
26273
26274pub fn multibuffer_context_lines(cx: &App) -> u32 {
26275    EditorSettings::try_get(cx)
26276        .map(|settings| settings.excerpt_context_lines)
26277        .unwrap_or(2)
26278        .min(32)
26279}