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    CompletionDetailAlignment, CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings,
   57    HideMouseMode, 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::{Restore, blame::BlameEntry, commit::ParsedCommitMessage, status::FileStatus};
   77use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   78use anyhow::{Context as _, Result, anyhow, bail};
   79use blink_manager::BlinkManager;
   80use buffer_diff::DiffHunkStatus;
   81use client::{Collaborator, ParticipantIndex, parse_zed_link};
   82use clock::ReplicaId;
   83use code_context_menus::{
   84    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   85    CompletionsMenu, ContextMenuOrigin,
   86};
   87use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   88use convert_case::{Case, Casing};
   89use dap::TelemetrySpawnLocation;
   90use display_map::*;
   91use edit_prediction_types::{
   92    EditPredictionDelegate, EditPredictionDelegateHandle, EditPredictionGranularity,
   93};
   94use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   95use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   96use futures::{
   97    FutureExt, StreamExt as _,
   98    future::{self, Shared, join},
   99    stream::FuturesUnordered,
  100};
  101use fuzzy::{StringMatch, StringMatchCandidate};
  102use git::blame::{GitBlame, GlobalBlameRenderer};
  103use gpui::{
  104    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  105    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  106    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  107    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  108    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, PressureStage,
  109    Render, ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, TextRun,
  110    TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle,
  111    WeakEntity, WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative,
  112    size,
  113};
  114use hover_links::{HoverLink, HoveredLinkState, find_file};
  115use hover_popover::{HoverState, hide_hover};
  116use indent_guides::ActiveIndentGuidesState;
  117use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  118use itertools::{Either, Itertools};
  119use language::{
  120    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  121    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  122    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  123    IndentSize, Language, LanguageName, LanguageRegistry, LanguageScope, OffsetRangeExt,
  124    OutlineItem, Point, Runnable, Selection, SelectionGoal, TextObject, TransactionId,
  125    TreeSitterOptions, WordsQuery,
  126    language_settings::{
  127        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  128        all_language_settings, language_settings,
  129    },
  130    point_from_lsp, point_to_lsp, text_diff_with_options,
  131};
  132use linked_editing_ranges::refresh_linked_ranges;
  133use lsp::{
  134    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  135    LanguageServerId,
  136};
  137use lsp_colors::LspColorData;
  138use markdown::Markdown;
  139use mouse_context_menu::MouseContextMenu;
  140use movement::TextLayoutDetails;
  141use multi_buffer::{
  142    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  143};
  144use parking_lot::Mutex;
  145use persistence::DB;
  146use project::{
  147    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  148    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  149    InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project,
  150    ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  151    debugger::{
  152        breakpoint_store::{
  153            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  154            BreakpointStore, BreakpointStoreEvent,
  155        },
  156        session::{Session, SessionEvent},
  157    },
  158    git_store::GitStoreEvent,
  159    lsp_store::{
  160        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  161        OpenLspBufferHandle,
  162    },
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  164};
  165use rand::seq::SliceRandom;
  166use regex::Regex;
  167use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  168use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  169use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  170use serde::{Deserialize, Serialize};
  171use settings::{
  172    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  173    update_settings_file,
  174};
  175use smallvec::{SmallVec, smallvec};
  176use snippet::Snippet;
  177use std::{
  178    any::{Any, TypeId},
  179    borrow::Cow,
  180    cell::{OnceCell, RefCell},
  181    cmp::{self, Ordering, Reverse},
  182    collections::hash_map,
  183    iter::{self, Peekable},
  184    mem,
  185    num::NonZeroU32,
  186    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  187    path::{Path, PathBuf},
  188    rc::Rc,
  189    sync::Arc,
  190    time::{Duration, Instant},
  191};
  192use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  193use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  194use theme::{
  195    AccentColors, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  196    observe_buffer_font_size_adjustment,
  197};
  198use ui::{
  199    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  200    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  201};
  202use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  203use workspace::{
  204    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  205    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  206    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  207    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  208    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  209    searchable::SearchEvent,
  210};
  211
  212use crate::{
  213    code_context_menus::CompletionsMenuSource,
  214    editor_settings::MultiCursorModifier,
  215    hover_links::{find_url, find_url_from_range},
  216    inlays::{
  217        InlineValueCache,
  218        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  219    },
  220    scroll::{ScrollOffset, ScrollPixelOffset},
  221    selections_collection::resolve_selections_wrapping_blocks,
  222    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  223};
  224
  225pub const FILE_HEADER_HEIGHT: u32 = 2;
  226pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  227const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  228const MAX_LINE_LEN: usize = 1024;
  229const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  230const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  231pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  232#[doc(hidden)]
  233pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  234pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  235
  236pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  237pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  238pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  239pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  240
  241pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  242pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  243pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  244
  245pub type RenderDiffHunkControlsFn = Arc<
  246    dyn Fn(
  247        u32,
  248        &DiffHunkStatus,
  249        Range<Anchor>,
  250        bool,
  251        Pixels,
  252        &Entity<Editor>,
  253        &mut Window,
  254        &mut App,
  255    ) -> AnyElement,
  256>;
  257
  258enum ReportEditorEvent {
  259    Saved { auto_saved: bool },
  260    EditorOpened,
  261    Closed,
  262}
  263
  264impl ReportEditorEvent {
  265    pub fn event_type(&self) -> &'static str {
  266        match self {
  267            Self::Saved { .. } => "Editor Saved",
  268            Self::EditorOpened => "Editor Opened",
  269            Self::Closed => "Editor Closed",
  270        }
  271    }
  272}
  273
  274pub enum ActiveDebugLine {}
  275pub enum DebugStackFrameLine {}
  276enum DocumentHighlightRead {}
  277enum DocumentHighlightWrite {}
  278enum InputComposition {}
  279pub enum PendingInput {}
  280enum SelectedTextHighlight {}
  281
  282pub enum ConflictsOuter {}
  283pub enum ConflictsOurs {}
  284pub enum ConflictsTheirs {}
  285pub enum ConflictsOursMarker {}
  286pub enum ConflictsTheirsMarker {}
  287
  288pub struct HunkAddedColor;
  289pub struct HunkRemovedColor;
  290
  291#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  292pub enum Navigated {
  293    Yes,
  294    No,
  295}
  296
  297impl Navigated {
  298    pub fn from_bool(yes: bool) -> Navigated {
  299        if yes { Navigated::Yes } else { Navigated::No }
  300    }
  301}
  302
  303#[derive(Debug, Clone, PartialEq, Eq)]
  304enum DisplayDiffHunk {
  305    Folded {
  306        display_row: DisplayRow,
  307    },
  308    Unfolded {
  309        is_created_file: bool,
  310        diff_base_byte_range: Range<usize>,
  311        display_row_range: Range<DisplayRow>,
  312        multi_buffer_range: Range<Anchor>,
  313        status: DiffHunkStatus,
  314        word_diffs: Vec<Range<MultiBufferOffset>>,
  315    },
  316}
  317
  318pub enum HideMouseCursorOrigin {
  319    TypingAction,
  320    MovementAction,
  321}
  322
  323pub fn init(cx: &mut App) {
  324    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  325
  326    workspace::register_project_item::<Editor>(cx);
  327    workspace::FollowableViewRegistry::register::<Editor>(cx);
  328    workspace::register_serializable_item::<Editor>(cx);
  329
  330    cx.observe_new(
  331        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  332            workspace.register_action(Editor::new_file);
  333            workspace.register_action(Editor::new_file_split);
  334            workspace.register_action(Editor::new_file_vertical);
  335            workspace.register_action(Editor::new_file_horizontal);
  336            workspace.register_action(Editor::cancel_language_server_work);
  337            workspace.register_action(Editor::toggle_focus);
  338        },
  339    )
  340    .detach();
  341
  342    cx.on_action(move |_: &workspace::NewFile, cx| {
  343        let app_state = workspace::AppState::global(cx);
  344        if let Some(app_state) = app_state.upgrade() {
  345            workspace::open_new(
  346                Default::default(),
  347                app_state,
  348                cx,
  349                |workspace, window, cx| {
  350                    Editor::new_file(workspace, &Default::default(), window, cx)
  351                },
  352            )
  353            .detach();
  354        }
  355    })
  356    .on_action(move |_: &workspace::NewWindow, cx| {
  357        let app_state = workspace::AppState::global(cx);
  358        if let Some(app_state) = app_state.upgrade() {
  359            workspace::open_new(
  360                Default::default(),
  361                app_state,
  362                cx,
  363                |workspace, window, cx| {
  364                    cx.activate(true);
  365                    Editor::new_file(workspace, &Default::default(), window, cx)
  366                },
  367            )
  368            .detach();
  369        }
  370    });
  371}
  372
  373pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  374    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  375}
  376
  377pub trait DiagnosticRenderer {
  378    fn render_group(
  379        &self,
  380        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  381        buffer_id: BufferId,
  382        snapshot: EditorSnapshot,
  383        editor: WeakEntity<Editor>,
  384        language_registry: Option<Arc<LanguageRegistry>>,
  385        cx: &mut App,
  386    ) -> Vec<BlockProperties<Anchor>>;
  387
  388    fn render_hover(
  389        &self,
  390        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  391        range: Range<Point>,
  392        buffer_id: BufferId,
  393        language_registry: Option<Arc<LanguageRegistry>>,
  394        cx: &mut App,
  395    ) -> Option<Entity<markdown::Markdown>>;
  396
  397    fn open_link(
  398        &self,
  399        editor: &mut Editor,
  400        link: SharedString,
  401        window: &mut Window,
  402        cx: &mut Context<Editor>,
  403    );
  404}
  405
  406pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  407
  408impl GlobalDiagnosticRenderer {
  409    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  410        cx.try_global::<Self>().map(|g| g.0.clone())
  411    }
  412}
  413
  414impl gpui::Global for GlobalDiagnosticRenderer {}
  415pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  416    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  417}
  418
  419pub struct SearchWithinRange;
  420
  421trait InvalidationRegion {
  422    fn ranges(&self) -> &[Range<Anchor>];
  423}
  424
  425#[derive(Clone, Debug, PartialEq)]
  426pub enum SelectPhase {
  427    Begin {
  428        position: DisplayPoint,
  429        add: bool,
  430        click_count: usize,
  431    },
  432    BeginColumnar {
  433        position: DisplayPoint,
  434        reset: bool,
  435        mode: ColumnarMode,
  436        goal_column: u32,
  437    },
  438    Extend {
  439        position: DisplayPoint,
  440        click_count: usize,
  441    },
  442    Update {
  443        position: DisplayPoint,
  444        goal_column: u32,
  445        scroll_delta: gpui::Point<f32>,
  446    },
  447    End,
  448}
  449
  450#[derive(Clone, Debug, PartialEq)]
  451pub enum ColumnarMode {
  452    FromMouse,
  453    FromSelection,
  454}
  455
  456#[derive(Clone, Debug)]
  457pub enum SelectMode {
  458    Character,
  459    Word(Range<Anchor>),
  460    Line(Range<Anchor>),
  461    All,
  462}
  463
  464#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  465pub enum SizingBehavior {
  466    /// The editor will layout itself using `size_full` and will include the vertical
  467    /// scroll margin as requested by user settings.
  468    #[default]
  469    Default,
  470    /// The editor will layout itself using `size_full`, but will not have any
  471    /// vertical overscroll.
  472    ExcludeOverscrollMargin,
  473    /// The editor will request a vertical size according to its content and will be
  474    /// layouted without a vertical scroll margin.
  475    SizeByContent,
  476}
  477
  478#[derive(Clone, PartialEq, Eq, Debug)]
  479pub enum EditorMode {
  480    SingleLine,
  481    AutoHeight {
  482        min_lines: usize,
  483        max_lines: Option<usize>,
  484    },
  485    Full {
  486        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  487        scale_ui_elements_with_buffer_font_size: bool,
  488        /// When set to `true`, the editor will render a background for the active line.
  489        show_active_line_background: bool,
  490        /// Determines the sizing behavior for this editor
  491        sizing_behavior: SizingBehavior,
  492    },
  493    Minimap {
  494        parent: WeakEntity<Editor>,
  495    },
  496}
  497
  498impl EditorMode {
  499    pub fn full() -> Self {
  500        Self::Full {
  501            scale_ui_elements_with_buffer_font_size: true,
  502            show_active_line_background: true,
  503            sizing_behavior: SizingBehavior::Default,
  504        }
  505    }
  506
  507    #[inline]
  508    pub fn is_full(&self) -> bool {
  509        matches!(self, Self::Full { .. })
  510    }
  511
  512    #[inline]
  513    pub fn is_single_line(&self) -> bool {
  514        matches!(self, Self::SingleLine { .. })
  515    }
  516
  517    #[inline]
  518    fn is_minimap(&self) -> bool {
  519        matches!(self, Self::Minimap { .. })
  520    }
  521}
  522
  523#[derive(Copy, Clone, Debug)]
  524pub enum SoftWrap {
  525    /// Prefer not to wrap at all.
  526    ///
  527    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  528    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  529    GitDiff,
  530    /// Prefer a single line generally, unless an overly long line is encountered.
  531    None,
  532    /// Soft wrap lines that exceed the editor width.
  533    EditorWidth,
  534    /// Soft wrap lines at the preferred line length.
  535    Column(u32),
  536    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  537    Bounded(u32),
  538}
  539
  540#[derive(Clone)]
  541pub struct EditorStyle {
  542    pub background: Hsla,
  543    pub border: Hsla,
  544    pub local_player: PlayerColor,
  545    pub text: TextStyle,
  546    pub scrollbar_width: Pixels,
  547    pub syntax: Arc<SyntaxTheme>,
  548    pub status: StatusColors,
  549    pub inlay_hints_style: HighlightStyle,
  550    pub edit_prediction_styles: EditPredictionStyles,
  551    pub unnecessary_code_fade: f32,
  552    pub show_underlines: bool,
  553}
  554
  555impl Default for EditorStyle {
  556    fn default() -> Self {
  557        Self {
  558            background: Hsla::default(),
  559            border: Hsla::default(),
  560            local_player: PlayerColor::default(),
  561            text: TextStyle::default(),
  562            scrollbar_width: Pixels::default(),
  563            syntax: Default::default(),
  564            // HACK: Status colors don't have a real default.
  565            // We should look into removing the status colors from the editor
  566            // style and retrieve them directly from the theme.
  567            status: StatusColors::dark(),
  568            inlay_hints_style: HighlightStyle::default(),
  569            edit_prediction_styles: EditPredictionStyles {
  570                insertion: HighlightStyle::default(),
  571                whitespace: HighlightStyle::default(),
  572            },
  573            unnecessary_code_fade: Default::default(),
  574            show_underlines: true,
  575        }
  576    }
  577}
  578
  579pub fn make_inlay_hints_style(cx: &App) -> HighlightStyle {
  580    let show_background = language_settings::language_settings(None, None, cx)
  581        .inlay_hints
  582        .show_background;
  583
  584    let mut style = cx.theme().syntax().get("hint");
  585
  586    if style.color.is_none() {
  587        style.color = Some(cx.theme().status().hint);
  588    }
  589
  590    if !show_background {
  591        style.background_color = None;
  592        return style;
  593    }
  594
  595    if style.background_color.is_none() {
  596        style.background_color = Some(cx.theme().status().hint_background);
  597    }
  598
  599    style
  600}
  601
  602pub fn make_suggestion_styles(cx: &App) -> EditPredictionStyles {
  603    EditPredictionStyles {
  604        insertion: HighlightStyle {
  605            color: Some(cx.theme().status().predictive),
  606            ..HighlightStyle::default()
  607        },
  608        whitespace: HighlightStyle {
  609            background_color: Some(cx.theme().status().created_background),
  610            ..HighlightStyle::default()
  611        },
  612    }
  613}
  614
  615type CompletionId = usize;
  616
  617pub(crate) enum EditDisplayMode {
  618    TabAccept,
  619    DiffPopover,
  620    Inline,
  621}
  622
  623enum EditPrediction {
  624    Edit {
  625        edits: Vec<(Range<Anchor>, Arc<str>)>,
  626        edit_preview: Option<EditPreview>,
  627        display_mode: EditDisplayMode,
  628        snapshot: BufferSnapshot,
  629    },
  630    /// Move to a specific location in the active editor
  631    MoveWithin {
  632        target: Anchor,
  633        snapshot: BufferSnapshot,
  634    },
  635    /// Move to a specific location in a different editor (not the active one)
  636    MoveOutside {
  637        target: language::Anchor,
  638        snapshot: BufferSnapshot,
  639    },
  640}
  641
  642struct EditPredictionState {
  643    inlay_ids: Vec<InlayId>,
  644    completion: EditPrediction,
  645    completion_id: Option<SharedString>,
  646    invalidation_range: Option<Range<Anchor>>,
  647}
  648
  649enum EditPredictionSettings {
  650    Disabled,
  651    Enabled {
  652        show_in_menu: bool,
  653        preview_requires_modifier: bool,
  654    },
  655}
  656
  657enum EditPredictionHighlight {}
  658
  659#[derive(Debug, Clone)]
  660struct InlineDiagnostic {
  661    message: SharedString,
  662    group_id: usize,
  663    is_primary: bool,
  664    start: Point,
  665    severity: lsp::DiagnosticSeverity,
  666}
  667
  668pub enum MenuEditPredictionsPolicy {
  669    Never,
  670    ByProvider,
  671}
  672
  673pub enum EditPredictionPreview {
  674    /// Modifier is not pressed
  675    Inactive { released_too_fast: bool },
  676    /// Modifier pressed
  677    Active {
  678        since: Instant,
  679        previous_scroll_position: Option<ScrollAnchor>,
  680    },
  681}
  682
  683impl EditPredictionPreview {
  684    pub fn released_too_fast(&self) -> bool {
  685        match self {
  686            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  687            EditPredictionPreview::Active { .. } => false,
  688        }
  689    }
  690
  691    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  692        if let EditPredictionPreview::Active {
  693            previous_scroll_position,
  694            ..
  695        } = self
  696        {
  697            *previous_scroll_position = scroll_position;
  698        }
  699    }
  700}
  701
  702pub struct ContextMenuOptions {
  703    pub min_entries_visible: usize,
  704    pub max_entries_visible: usize,
  705    pub placement: Option<ContextMenuPlacement>,
  706}
  707
  708#[derive(Debug, Clone, PartialEq, Eq)]
  709pub enum ContextMenuPlacement {
  710    Above,
  711    Below,
  712}
  713
  714#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  715struct EditorActionId(usize);
  716
  717impl EditorActionId {
  718    pub fn post_inc(&mut self) -> Self {
  719        let answer = self.0;
  720
  721        *self = Self(answer + 1);
  722
  723        Self(answer)
  724    }
  725}
  726
  727// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  728// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  729
  730type BackgroundHighlight = (
  731    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  732    Arc<[Range<Anchor>]>,
  733);
  734type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  735
  736#[derive(Default)]
  737struct ScrollbarMarkerState {
  738    scrollbar_size: Size<Pixels>,
  739    dirty: bool,
  740    markers: Arc<[PaintQuad]>,
  741    pending_refresh: Option<Task<Result<()>>>,
  742}
  743
  744impl ScrollbarMarkerState {
  745    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  746        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  747    }
  748}
  749
  750#[derive(Clone, Copy, PartialEq, Eq)]
  751pub enum MinimapVisibility {
  752    Disabled,
  753    Enabled {
  754        /// The configuration currently present in the users settings.
  755        setting_configuration: bool,
  756        /// Whether to override the currently set visibility from the users setting.
  757        toggle_override: bool,
  758    },
  759}
  760
  761impl MinimapVisibility {
  762    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  763        if mode.is_full() {
  764            Self::Enabled {
  765                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  766                toggle_override: false,
  767            }
  768        } else {
  769            Self::Disabled
  770        }
  771    }
  772
  773    fn hidden(&self) -> Self {
  774        match *self {
  775            Self::Enabled {
  776                setting_configuration,
  777                ..
  778            } => Self::Enabled {
  779                setting_configuration,
  780                toggle_override: setting_configuration,
  781            },
  782            Self::Disabled => Self::Disabled,
  783        }
  784    }
  785
  786    fn disabled(&self) -> bool {
  787        matches!(*self, Self::Disabled)
  788    }
  789
  790    fn settings_visibility(&self) -> bool {
  791        match *self {
  792            Self::Enabled {
  793                setting_configuration,
  794                ..
  795            } => setting_configuration,
  796            _ => false,
  797        }
  798    }
  799
  800    fn visible(&self) -> bool {
  801        match *self {
  802            Self::Enabled {
  803                setting_configuration,
  804                toggle_override,
  805            } => setting_configuration ^ toggle_override,
  806            _ => false,
  807        }
  808    }
  809
  810    fn toggle_visibility(&self) -> Self {
  811        match *self {
  812            Self::Enabled {
  813                toggle_override,
  814                setting_configuration,
  815            } => Self::Enabled {
  816                setting_configuration,
  817                toggle_override: !toggle_override,
  818            },
  819            Self::Disabled => Self::Disabled,
  820        }
  821    }
  822}
  823
  824#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  825pub enum BufferSerialization {
  826    All,
  827    NonDirtyBuffers,
  828}
  829
  830impl BufferSerialization {
  831    fn new(restore_unsaved_buffers: bool) -> Self {
  832        if restore_unsaved_buffers {
  833            Self::All
  834        } else {
  835            Self::NonDirtyBuffers
  836        }
  837    }
  838}
  839
  840#[derive(Clone, Debug)]
  841struct RunnableTasks {
  842    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  843    offset: multi_buffer::Anchor,
  844    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  845    column: u32,
  846    // Values of all named captures, including those starting with '_'
  847    extra_variables: HashMap<String, String>,
  848    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  849    context_range: Range<BufferOffset>,
  850}
  851
  852impl RunnableTasks {
  853    fn resolve<'a>(
  854        &'a self,
  855        cx: &'a task::TaskContext,
  856    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  857        self.templates.iter().filter_map(|(kind, template)| {
  858            template
  859                .resolve_task(&kind.to_id_base(), cx)
  860                .map(|task| (kind.clone(), task))
  861        })
  862    }
  863}
  864
  865#[derive(Clone)]
  866pub struct ResolvedTasks {
  867    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  868    position: Anchor,
  869}
  870
  871/// Addons allow storing per-editor state in other crates (e.g. Vim)
  872pub trait Addon: 'static {
  873    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  874
  875    fn render_buffer_header_controls(
  876        &self,
  877        _: &ExcerptInfo,
  878        _: &Window,
  879        _: &App,
  880    ) -> Option<AnyElement> {
  881        None
  882    }
  883
  884    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  885        None
  886    }
  887
  888    fn to_any(&self) -> &dyn std::any::Any;
  889
  890    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  891        None
  892    }
  893}
  894
  895struct ChangeLocation {
  896    current: Option<Vec<Anchor>>,
  897    original: Vec<Anchor>,
  898}
  899impl ChangeLocation {
  900    fn locations(&self) -> &[Anchor] {
  901        self.current.as_ref().unwrap_or(&self.original)
  902    }
  903}
  904
  905/// A set of caret positions, registered when the editor was edited.
  906pub struct ChangeList {
  907    changes: Vec<ChangeLocation>,
  908    /// Currently "selected" change.
  909    position: Option<usize>,
  910}
  911
  912impl ChangeList {
  913    pub fn new() -> Self {
  914        Self {
  915            changes: Vec::new(),
  916            position: None,
  917        }
  918    }
  919
  920    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  921    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  922    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  923        if self.changes.is_empty() {
  924            return None;
  925        }
  926
  927        let prev = self.position.unwrap_or(self.changes.len());
  928        let next = if direction == Direction::Prev {
  929            prev.saturating_sub(count)
  930        } else {
  931            (prev + count).min(self.changes.len() - 1)
  932        };
  933        self.position = Some(next);
  934        self.changes.get(next).map(|change| change.locations())
  935    }
  936
  937    /// Adds a new change to the list, resetting the change list position.
  938    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  939        self.position.take();
  940        if let Some(last) = self.changes.last_mut()
  941            && group
  942        {
  943            last.current = Some(new_positions)
  944        } else {
  945            self.changes.push(ChangeLocation {
  946                original: new_positions,
  947                current: None,
  948            });
  949        }
  950    }
  951
  952    pub fn last(&self) -> Option<&[Anchor]> {
  953        self.changes.last().map(|change| change.locations())
  954    }
  955
  956    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  957        self.changes.last().map(|change| change.original.as_slice())
  958    }
  959
  960    pub fn invert_last_group(&mut self) {
  961        if let Some(last) = self.changes.last_mut()
  962            && let Some(current) = last.current.as_mut()
  963        {
  964            mem::swap(&mut last.original, current);
  965        }
  966    }
  967}
  968
  969#[derive(Clone)]
  970struct InlineBlamePopoverState {
  971    scroll_handle: ScrollHandle,
  972    commit_message: Option<ParsedCommitMessage>,
  973    markdown: Entity<Markdown>,
  974}
  975
  976struct InlineBlamePopover {
  977    position: gpui::Point<Pixels>,
  978    hide_task: Option<Task<()>>,
  979    popover_bounds: Option<Bounds<Pixels>>,
  980    popover_state: InlineBlamePopoverState,
  981    keyboard_grace: bool,
  982}
  983
  984enum SelectionDragState {
  985    /// State when no drag related activity is detected.
  986    None,
  987    /// State when the mouse is down on a selection that is about to be dragged.
  988    ReadyToDrag {
  989        selection: Selection<Anchor>,
  990        click_position: gpui::Point<Pixels>,
  991        mouse_down_time: Instant,
  992    },
  993    /// State when the mouse is dragging the selection in the editor.
  994    Dragging {
  995        selection: Selection<Anchor>,
  996        drop_cursor: Selection<Anchor>,
  997        hide_drop_cursor: bool,
  998    },
  999}
 1000
 1001enum ColumnarSelectionState {
 1002    FromMouse {
 1003        selection_tail: Anchor,
 1004        display_point: Option<DisplayPoint>,
 1005    },
 1006    FromSelection {
 1007        selection_tail: Anchor,
 1008    },
 1009}
 1010
 1011/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1012/// a breakpoint on them.
 1013#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1014struct PhantomBreakpointIndicator {
 1015    display_row: DisplayRow,
 1016    /// There's a small debounce between hovering over the line and showing the indicator.
 1017    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1018    is_active: bool,
 1019    collides_with_existing_breakpoint: bool,
 1020}
 1021
 1022/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1023///
 1024/// See the [module level documentation](self) for more information.
 1025pub struct Editor {
 1026    focus_handle: FocusHandle,
 1027    last_focused_descendant: Option<WeakFocusHandle>,
 1028    /// The text buffer being edited
 1029    buffer: Entity<MultiBuffer>,
 1030    /// Map of how text in the buffer should be displayed.
 1031    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1032    pub display_map: Entity<DisplayMap>,
 1033    placeholder_display_map: Option<Entity<DisplayMap>>,
 1034    pub selections: SelectionsCollection,
 1035    pub scroll_manager: ScrollManager,
 1036    /// When inline assist editors are linked, they all render cursors because
 1037    /// typing enters text into each of them, even the ones that aren't focused.
 1038    pub(crate) show_cursor_when_unfocused: bool,
 1039    columnar_selection_state: Option<ColumnarSelectionState>,
 1040    add_selections_state: Option<AddSelectionsState>,
 1041    select_next_state: Option<SelectNextState>,
 1042    select_prev_state: Option<SelectNextState>,
 1043    selection_history: SelectionHistory,
 1044    defer_selection_effects: bool,
 1045    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1046    autoclose_regions: Vec<AutocloseRegion>,
 1047    snippet_stack: InvalidationStack<SnippetState>,
 1048    select_syntax_node_history: SelectSyntaxNodeHistory,
 1049    ime_transaction: Option<TransactionId>,
 1050    pub diagnostics_max_severity: DiagnosticSeverity,
 1051    active_diagnostics: ActiveDiagnostic,
 1052    show_inline_diagnostics: bool,
 1053    inline_diagnostics_update: Task<()>,
 1054    inline_diagnostics_enabled: bool,
 1055    diagnostics_enabled: bool,
 1056    word_completions_enabled: bool,
 1057    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1058    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1059    hard_wrap: Option<usize>,
 1060    project: Option<Entity<Project>>,
 1061    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1062    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1063    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1064    blink_manager: Entity<BlinkManager>,
 1065    show_cursor_names: bool,
 1066    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1067    pub show_local_selections: bool,
 1068    mode: EditorMode,
 1069    show_breadcrumbs: bool,
 1070    show_gutter: bool,
 1071    show_scrollbars: ScrollbarAxes,
 1072    minimap_visibility: MinimapVisibility,
 1073    offset_content: bool,
 1074    disable_expand_excerpt_buttons: bool,
 1075    delegate_expand_excerpts: bool,
 1076    show_line_numbers: Option<bool>,
 1077    use_relative_line_numbers: Option<bool>,
 1078    show_git_diff_gutter: Option<bool>,
 1079    show_code_actions: Option<bool>,
 1080    show_runnables: Option<bool>,
 1081    show_breakpoints: Option<bool>,
 1082    show_wrap_guides: Option<bool>,
 1083    show_indent_guides: Option<bool>,
 1084    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1085    highlight_order: usize,
 1086    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1087    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1088    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1089    scrollbar_marker_state: ScrollbarMarkerState,
 1090    active_indent_guides_state: ActiveIndentGuidesState,
 1091    nav_history: Option<ItemNavHistory>,
 1092    context_menu: RefCell<Option<CodeContextMenu>>,
 1093    context_menu_options: Option<ContextMenuOptions>,
 1094    mouse_context_menu: Option<MouseContextMenu>,
 1095    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1096    inline_blame_popover: Option<InlineBlamePopover>,
 1097    inline_blame_popover_show_task: Option<Task<()>>,
 1098    signature_help_state: SignatureHelpState,
 1099    auto_signature_help: Option<bool>,
 1100    find_all_references_task_sources: Vec<Anchor>,
 1101    next_completion_id: CompletionId,
 1102    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1103    code_actions_task: Option<Task<Result<()>>>,
 1104    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1105    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1106    document_highlights_task: Option<Task<()>>,
 1107    linked_editing_range_task: Option<Task<Option<()>>>,
 1108    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1109    pending_rename: Option<RenameState>,
 1110    searchable: bool,
 1111    cursor_shape: CursorShape,
 1112    /// Whether the cursor is offset one character to the left when something is
 1113    /// selected (needed for vim visual mode)
 1114    cursor_offset_on_selection: bool,
 1115    current_line_highlight: Option<CurrentLineHighlight>,
 1116    pub collapse_matches: bool,
 1117    autoindent_mode: Option<AutoindentMode>,
 1118    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1119    input_enabled: bool,
 1120    use_modal_editing: bool,
 1121    read_only: bool,
 1122    leader_id: Option<CollaboratorId>,
 1123    remote_id: Option<ViewId>,
 1124    pub hover_state: HoverState,
 1125    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1126    prev_pressure_stage: Option<PressureStage>,
 1127    gutter_hovered: bool,
 1128    hovered_link_state: Option<HoveredLinkState>,
 1129    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1130    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1131    active_edit_prediction: Option<EditPredictionState>,
 1132    /// Used to prevent flickering as the user types while the menu is open
 1133    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1134    edit_prediction_settings: EditPredictionSettings,
 1135    edit_predictions_hidden_for_vim_mode: bool,
 1136    show_edit_predictions_override: Option<bool>,
 1137    show_completions_on_input_override: Option<bool>,
 1138    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1139    edit_prediction_preview: EditPredictionPreview,
 1140    edit_prediction_indent_conflict: bool,
 1141    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1142    next_inlay_id: usize,
 1143    next_color_inlay_id: usize,
 1144    _subscriptions: Vec<Subscription>,
 1145    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1146    gutter_dimensions: GutterDimensions,
 1147    style: Option<EditorStyle>,
 1148    text_style_refinement: Option<TextStyleRefinement>,
 1149    next_editor_action_id: EditorActionId,
 1150    editor_actions: Rc<
 1151        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1152    >,
 1153    use_autoclose: bool,
 1154    use_auto_surround: bool,
 1155    auto_replace_emoji_shortcode: bool,
 1156    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1157    show_git_blame_gutter: bool,
 1158    show_git_blame_inline: bool,
 1159    show_git_blame_inline_delay_task: Option<Task<()>>,
 1160    git_blame_inline_enabled: bool,
 1161    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1162    buffer_serialization: Option<BufferSerialization>,
 1163    show_selection_menu: Option<bool>,
 1164    blame: Option<Entity<GitBlame>>,
 1165    blame_subscription: Option<Subscription>,
 1166    custom_context_menu: Option<
 1167        Box<
 1168            dyn 'static
 1169                + Fn(
 1170                    &mut Self,
 1171                    DisplayPoint,
 1172                    &mut Window,
 1173                    &mut Context<Self>,
 1174                ) -> Option<Entity<ui::ContextMenu>>,
 1175        >,
 1176    >,
 1177    last_bounds: Option<Bounds<Pixels>>,
 1178    last_position_map: Option<Rc<PositionMap>>,
 1179    expect_bounds_change: Option<Bounds<Pixels>>,
 1180    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1181    tasks_update_task: Option<Task<()>>,
 1182    breakpoint_store: Option<Entity<BreakpointStore>>,
 1183    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1184    hovered_diff_hunk_row: Option<DisplayRow>,
 1185    pull_diagnostics_task: Task<()>,
 1186    pull_diagnostics_background_task: Task<()>,
 1187    in_project_search: bool,
 1188    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1189    breadcrumb_header: Option<String>,
 1190    focused_block: Option<FocusedBlock>,
 1191    next_scroll_position: NextScrollCursorCenterTopBottom,
 1192    addons: HashMap<TypeId, Box<dyn Addon>>,
 1193    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1194    load_diff_task: Option<Shared<Task<()>>>,
 1195    /// Whether we are temporarily displaying a diff other than git's
 1196    temporary_diff_override: bool,
 1197    selection_mark_mode: bool,
 1198    toggle_fold_multiple_buffers: Task<()>,
 1199    _scroll_cursor_center_top_bottom_task: Task<()>,
 1200    serialize_selections: Task<()>,
 1201    serialize_folds: Task<()>,
 1202    mouse_cursor_hidden: bool,
 1203    minimap: Option<Entity<Self>>,
 1204    hide_mouse_mode: HideMouseMode,
 1205    pub change_list: ChangeList,
 1206    inline_value_cache: InlineValueCache,
 1207    number_deleted_lines: bool,
 1208
 1209    selection_drag_state: SelectionDragState,
 1210    colors: Option<LspColorData>,
 1211    post_scroll_update: Task<()>,
 1212    refresh_colors_task: Task<()>,
 1213    inlay_hints: Option<LspInlayHintData>,
 1214    folding_newlines: Task<()>,
 1215    select_next_is_case_sensitive: Option<bool>,
 1216    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1217    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1218    accent_data: Option<AccentData>,
 1219    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1220}
 1221
 1222#[derive(Debug, PartialEq)]
 1223struct AccentData {
 1224    colors: AccentColors,
 1225    overrides: Vec<SharedString>,
 1226}
 1227
 1228fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1229    if debounce_ms > 0 {
 1230        Some(Duration::from_millis(debounce_ms))
 1231    } else {
 1232        None
 1233    }
 1234}
 1235
 1236#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1237enum NextScrollCursorCenterTopBottom {
 1238    #[default]
 1239    Center,
 1240    Top,
 1241    Bottom,
 1242}
 1243
 1244impl NextScrollCursorCenterTopBottom {
 1245    fn next(&self) -> Self {
 1246        match self {
 1247            Self::Center => Self::Top,
 1248            Self::Top => Self::Bottom,
 1249            Self::Bottom => Self::Center,
 1250        }
 1251    }
 1252}
 1253
 1254#[derive(Clone)]
 1255pub struct EditorSnapshot {
 1256    pub mode: EditorMode,
 1257    show_gutter: bool,
 1258    offset_content: bool,
 1259    show_line_numbers: Option<bool>,
 1260    number_deleted_lines: bool,
 1261    show_git_diff_gutter: Option<bool>,
 1262    show_code_actions: Option<bool>,
 1263    show_runnables: Option<bool>,
 1264    show_breakpoints: Option<bool>,
 1265    git_blame_gutter_max_author_length: Option<usize>,
 1266    pub display_snapshot: DisplaySnapshot,
 1267    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1268    is_focused: bool,
 1269    scroll_anchor: ScrollAnchor,
 1270    ongoing_scroll: OngoingScroll,
 1271    current_line_highlight: CurrentLineHighlight,
 1272    gutter_hovered: bool,
 1273}
 1274
 1275#[derive(Default, Debug, Clone, Copy)]
 1276pub struct GutterDimensions {
 1277    pub left_padding: Pixels,
 1278    pub right_padding: Pixels,
 1279    pub width: Pixels,
 1280    pub margin: Pixels,
 1281    pub git_blame_entries_width: Option<Pixels>,
 1282}
 1283
 1284impl GutterDimensions {
 1285    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1286        Self {
 1287            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1288            ..Default::default()
 1289        }
 1290    }
 1291
 1292    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1293        -cx.text_system().descent(font_id, font_size)
 1294    }
 1295    /// The full width of the space taken up by the gutter.
 1296    pub fn full_width(&self) -> Pixels {
 1297        self.margin + self.width
 1298    }
 1299
 1300    /// The width of the space reserved for the fold indicators,
 1301    /// use alongside 'justify_end' and `gutter_width` to
 1302    /// right align content with the line numbers
 1303    pub fn fold_area_width(&self) -> Pixels {
 1304        self.margin + self.right_padding
 1305    }
 1306}
 1307
 1308struct CharacterDimensions {
 1309    em_width: Pixels,
 1310    em_advance: Pixels,
 1311    line_height: Pixels,
 1312}
 1313
 1314#[derive(Debug)]
 1315pub struct RemoteSelection {
 1316    pub replica_id: ReplicaId,
 1317    pub selection: Selection<Anchor>,
 1318    pub cursor_shape: CursorShape,
 1319    pub collaborator_id: CollaboratorId,
 1320    pub line_mode: bool,
 1321    pub user_name: Option<SharedString>,
 1322    pub color: PlayerColor,
 1323}
 1324
 1325#[derive(Clone, Debug)]
 1326struct SelectionHistoryEntry {
 1327    selections: Arc<[Selection<Anchor>]>,
 1328    select_next_state: Option<SelectNextState>,
 1329    select_prev_state: Option<SelectNextState>,
 1330    add_selections_state: Option<AddSelectionsState>,
 1331}
 1332
 1333#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1334enum SelectionHistoryMode {
 1335    #[default]
 1336    Normal,
 1337    Undoing,
 1338    Redoing,
 1339    Skipping,
 1340}
 1341
 1342#[derive(Clone, PartialEq, Eq, Hash)]
 1343struct HoveredCursor {
 1344    replica_id: ReplicaId,
 1345    selection_id: usize,
 1346}
 1347
 1348#[derive(Debug)]
 1349/// SelectionEffects controls the side-effects of updating the selection.
 1350///
 1351/// The default behaviour does "what you mostly want":
 1352/// - it pushes to the nav history if the cursor moved by >10 lines
 1353/// - it re-triggers completion requests
 1354/// - it scrolls to fit
 1355///
 1356/// You might want to modify these behaviours. For example when doing a "jump"
 1357/// like go to definition, we always want to add to nav history; but when scrolling
 1358/// in vim mode we never do.
 1359///
 1360/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1361/// move.
 1362#[derive(Clone)]
 1363pub struct SelectionEffects {
 1364    nav_history: Option<bool>,
 1365    completions: bool,
 1366    scroll: Option<Autoscroll>,
 1367}
 1368
 1369impl Default for SelectionEffects {
 1370    fn default() -> Self {
 1371        Self {
 1372            nav_history: None,
 1373            completions: true,
 1374            scroll: Some(Autoscroll::fit()),
 1375        }
 1376    }
 1377}
 1378impl SelectionEffects {
 1379    pub fn scroll(scroll: Autoscroll) -> Self {
 1380        Self {
 1381            scroll: Some(scroll),
 1382            ..Default::default()
 1383        }
 1384    }
 1385
 1386    pub fn no_scroll() -> Self {
 1387        Self {
 1388            scroll: None,
 1389            ..Default::default()
 1390        }
 1391    }
 1392
 1393    pub fn completions(self, completions: bool) -> Self {
 1394        Self {
 1395            completions,
 1396            ..self
 1397        }
 1398    }
 1399
 1400    pub fn nav_history(self, nav_history: bool) -> Self {
 1401        Self {
 1402            nav_history: Some(nav_history),
 1403            ..self
 1404        }
 1405    }
 1406}
 1407
 1408struct DeferredSelectionEffectsState {
 1409    changed: bool,
 1410    effects: SelectionEffects,
 1411    old_cursor_position: Anchor,
 1412    history_entry: SelectionHistoryEntry,
 1413}
 1414
 1415#[derive(Default)]
 1416struct SelectionHistory {
 1417    #[allow(clippy::type_complexity)]
 1418    selections_by_transaction:
 1419        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1420    mode: SelectionHistoryMode,
 1421    undo_stack: VecDeque<SelectionHistoryEntry>,
 1422    redo_stack: VecDeque<SelectionHistoryEntry>,
 1423}
 1424
 1425impl SelectionHistory {
 1426    #[track_caller]
 1427    fn insert_transaction(
 1428        &mut self,
 1429        transaction_id: TransactionId,
 1430        selections: Arc<[Selection<Anchor>]>,
 1431    ) {
 1432        if selections.is_empty() {
 1433            log::error!(
 1434                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1435                std::panic::Location::caller()
 1436            );
 1437            return;
 1438        }
 1439        self.selections_by_transaction
 1440            .insert(transaction_id, (selections, None));
 1441    }
 1442
 1443    #[allow(clippy::type_complexity)]
 1444    fn transaction(
 1445        &self,
 1446        transaction_id: TransactionId,
 1447    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1448        self.selections_by_transaction.get(&transaction_id)
 1449    }
 1450
 1451    #[allow(clippy::type_complexity)]
 1452    fn transaction_mut(
 1453        &mut self,
 1454        transaction_id: TransactionId,
 1455    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1456        self.selections_by_transaction.get_mut(&transaction_id)
 1457    }
 1458
 1459    fn push(&mut self, entry: SelectionHistoryEntry) {
 1460        if !entry.selections.is_empty() {
 1461            match self.mode {
 1462                SelectionHistoryMode::Normal => {
 1463                    self.push_undo(entry);
 1464                    self.redo_stack.clear();
 1465                }
 1466                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1467                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1468                SelectionHistoryMode::Skipping => {}
 1469            }
 1470        }
 1471    }
 1472
 1473    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1474        if self
 1475            .undo_stack
 1476            .back()
 1477            .is_none_or(|e| e.selections != entry.selections)
 1478        {
 1479            self.undo_stack.push_back(entry);
 1480            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1481                self.undo_stack.pop_front();
 1482            }
 1483        }
 1484    }
 1485
 1486    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1487        if self
 1488            .redo_stack
 1489            .back()
 1490            .is_none_or(|e| e.selections != entry.selections)
 1491        {
 1492            self.redo_stack.push_back(entry);
 1493            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1494                self.redo_stack.pop_front();
 1495            }
 1496        }
 1497    }
 1498}
 1499
 1500#[derive(Clone, Copy)]
 1501pub struct RowHighlightOptions {
 1502    pub autoscroll: bool,
 1503    pub include_gutter: bool,
 1504}
 1505
 1506impl Default for RowHighlightOptions {
 1507    fn default() -> Self {
 1508        Self {
 1509            autoscroll: Default::default(),
 1510            include_gutter: true,
 1511        }
 1512    }
 1513}
 1514
 1515struct RowHighlight {
 1516    index: usize,
 1517    range: Range<Anchor>,
 1518    color: Hsla,
 1519    options: RowHighlightOptions,
 1520    type_id: TypeId,
 1521}
 1522
 1523#[derive(Clone, Debug)]
 1524struct AddSelectionsState {
 1525    groups: Vec<AddSelectionsGroup>,
 1526}
 1527
 1528#[derive(Clone, Debug)]
 1529struct AddSelectionsGroup {
 1530    above: bool,
 1531    stack: Vec<usize>,
 1532}
 1533
 1534#[derive(Clone)]
 1535struct SelectNextState {
 1536    query: AhoCorasick,
 1537    wordwise: bool,
 1538    done: bool,
 1539}
 1540
 1541impl std::fmt::Debug for SelectNextState {
 1542    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1543        f.debug_struct(std::any::type_name::<Self>())
 1544            .field("wordwise", &self.wordwise)
 1545            .field("done", &self.done)
 1546            .finish()
 1547    }
 1548}
 1549
 1550#[derive(Debug)]
 1551struct AutocloseRegion {
 1552    selection_id: usize,
 1553    range: Range<Anchor>,
 1554    pair: BracketPair,
 1555}
 1556
 1557#[derive(Debug)]
 1558struct SnippetState {
 1559    ranges: Vec<Vec<Range<Anchor>>>,
 1560    active_index: usize,
 1561    choices: Vec<Option<Vec<String>>>,
 1562}
 1563
 1564#[doc(hidden)]
 1565pub struct RenameState {
 1566    pub range: Range<Anchor>,
 1567    pub old_name: Arc<str>,
 1568    pub editor: Entity<Editor>,
 1569    block_id: CustomBlockId,
 1570}
 1571
 1572struct InvalidationStack<T>(Vec<T>);
 1573
 1574struct RegisteredEditPredictionDelegate {
 1575    provider: Arc<dyn EditPredictionDelegateHandle>,
 1576    _subscription: Subscription,
 1577}
 1578
 1579#[derive(Debug, PartialEq, Eq)]
 1580pub struct ActiveDiagnosticGroup {
 1581    pub active_range: Range<Anchor>,
 1582    pub active_message: String,
 1583    pub group_id: usize,
 1584    pub blocks: HashSet<CustomBlockId>,
 1585}
 1586
 1587#[derive(Debug, PartialEq, Eq)]
 1588
 1589pub(crate) enum ActiveDiagnostic {
 1590    None,
 1591    All,
 1592    Group(ActiveDiagnosticGroup),
 1593}
 1594
 1595#[derive(Serialize, Deserialize, Clone, Debug)]
 1596pub struct ClipboardSelection {
 1597    /// The number of bytes in this selection.
 1598    pub len: usize,
 1599    /// Whether this was a full-line selection.
 1600    pub is_entire_line: bool,
 1601    /// The indentation of the first line when this content was originally copied.
 1602    pub first_line_indent: u32,
 1603    #[serde(default)]
 1604    pub file_path: Option<PathBuf>,
 1605    #[serde(default)]
 1606    pub line_range: Option<RangeInclusive<u32>>,
 1607}
 1608
 1609impl ClipboardSelection {
 1610    pub fn for_buffer(
 1611        len: usize,
 1612        is_entire_line: bool,
 1613        range: Range<Point>,
 1614        buffer: &MultiBufferSnapshot,
 1615        project: Option<&Entity<Project>>,
 1616        cx: &App,
 1617    ) -> Self {
 1618        let first_line_indent = buffer
 1619            .indent_size_for_line(MultiBufferRow(range.start.row))
 1620            .len;
 1621
 1622        let file_path = util::maybe!({
 1623            let project = project?.read(cx);
 1624            let file = buffer.file_at(range.start)?;
 1625            let project_path = ProjectPath {
 1626                worktree_id: file.worktree_id(cx),
 1627                path: file.path().clone(),
 1628            };
 1629            project.absolute_path(&project_path, cx)
 1630        });
 1631
 1632        let line_range = file_path.as_ref().map(|_| range.start.row..=range.end.row);
 1633
 1634        Self {
 1635            len,
 1636            is_entire_line,
 1637            first_line_indent,
 1638            file_path,
 1639            line_range,
 1640        }
 1641    }
 1642}
 1643
 1644// selections, scroll behavior, was newest selection reversed
 1645type SelectSyntaxNodeHistoryState = (
 1646    Box<[Selection<MultiBufferOffset>]>,
 1647    SelectSyntaxNodeScrollBehavior,
 1648    bool,
 1649);
 1650
 1651#[derive(Default)]
 1652struct SelectSyntaxNodeHistory {
 1653    stack: Vec<SelectSyntaxNodeHistoryState>,
 1654    // disable temporarily to allow changing selections without losing the stack
 1655    pub disable_clearing: bool,
 1656}
 1657
 1658impl SelectSyntaxNodeHistory {
 1659    pub fn try_clear(&mut self) {
 1660        if !self.disable_clearing {
 1661            self.stack.clear();
 1662        }
 1663    }
 1664
 1665    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1666        self.stack.push(selection);
 1667    }
 1668
 1669    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1670        self.stack.pop()
 1671    }
 1672}
 1673
 1674enum SelectSyntaxNodeScrollBehavior {
 1675    CursorTop,
 1676    FitSelection,
 1677    CursorBottom,
 1678}
 1679
 1680#[derive(Debug)]
 1681pub(crate) struct NavigationData {
 1682    cursor_anchor: Anchor,
 1683    cursor_position: Point,
 1684    scroll_anchor: ScrollAnchor,
 1685    scroll_top_row: u32,
 1686}
 1687
 1688#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1689pub enum GotoDefinitionKind {
 1690    Symbol,
 1691    Declaration,
 1692    Type,
 1693    Implementation,
 1694}
 1695
 1696pub enum FormatTarget {
 1697    Buffers(HashSet<Entity<Buffer>>),
 1698    Ranges(Vec<Range<MultiBufferPoint>>),
 1699}
 1700
 1701pub(crate) struct FocusedBlock {
 1702    id: BlockId,
 1703    focus_handle: WeakFocusHandle,
 1704}
 1705
 1706#[derive(Clone, Debug)]
 1707enum JumpData {
 1708    MultiBufferRow {
 1709        row: MultiBufferRow,
 1710        line_offset_from_top: u32,
 1711    },
 1712    MultiBufferPoint {
 1713        excerpt_id: ExcerptId,
 1714        position: Point,
 1715        anchor: text::Anchor,
 1716        line_offset_from_top: u32,
 1717    },
 1718}
 1719
 1720pub enum MultibufferSelectionMode {
 1721    First,
 1722    All,
 1723}
 1724
 1725#[derive(Clone, Copy, Debug, Default)]
 1726pub struct RewrapOptions {
 1727    pub override_language_settings: bool,
 1728    pub preserve_existing_whitespace: bool,
 1729}
 1730
 1731impl Editor {
 1732    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1733        let buffer = cx.new(|cx| Buffer::local("", cx));
 1734        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1735        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1736    }
 1737
 1738    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1739        let buffer = cx.new(|cx| Buffer::local("", cx));
 1740        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1741        Self::new(EditorMode::full(), buffer, None, window, cx)
 1742    }
 1743
 1744    pub fn auto_height(
 1745        min_lines: usize,
 1746        max_lines: usize,
 1747        window: &mut Window,
 1748        cx: &mut Context<Self>,
 1749    ) -> Self {
 1750        let buffer = cx.new(|cx| Buffer::local("", cx));
 1751        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1752        Self::new(
 1753            EditorMode::AutoHeight {
 1754                min_lines,
 1755                max_lines: Some(max_lines),
 1756            },
 1757            buffer,
 1758            None,
 1759            window,
 1760            cx,
 1761        )
 1762    }
 1763
 1764    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1765    /// The editor grows as tall as needed to fit its content.
 1766    pub fn auto_height_unbounded(
 1767        min_lines: usize,
 1768        window: &mut Window,
 1769        cx: &mut Context<Self>,
 1770    ) -> Self {
 1771        let buffer = cx.new(|cx| Buffer::local("", cx));
 1772        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1773        Self::new(
 1774            EditorMode::AutoHeight {
 1775                min_lines,
 1776                max_lines: None,
 1777            },
 1778            buffer,
 1779            None,
 1780            window,
 1781            cx,
 1782        )
 1783    }
 1784
 1785    pub fn for_buffer(
 1786        buffer: Entity<Buffer>,
 1787        project: Option<Entity<Project>>,
 1788        window: &mut Window,
 1789        cx: &mut Context<Self>,
 1790    ) -> Self {
 1791        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1792        Self::new(EditorMode::full(), buffer, project, window, cx)
 1793    }
 1794
 1795    pub fn for_multibuffer(
 1796        buffer: Entity<MultiBuffer>,
 1797        project: Option<Entity<Project>>,
 1798        window: &mut Window,
 1799        cx: &mut Context<Self>,
 1800    ) -> Self {
 1801        Self::new(EditorMode::full(), buffer, project, window, cx)
 1802    }
 1803
 1804    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1805        let mut clone = Self::new(
 1806            self.mode.clone(),
 1807            self.buffer.clone(),
 1808            self.project.clone(),
 1809            window,
 1810            cx,
 1811        );
 1812        self.display_map.update(cx, |display_map, cx| {
 1813            let snapshot = display_map.snapshot(cx);
 1814            clone.display_map.update(cx, |display_map, cx| {
 1815                display_map.set_state(&snapshot, cx);
 1816            });
 1817        });
 1818        clone.folds_did_change(cx);
 1819        clone.selections.clone_state(&self.selections);
 1820        clone.scroll_manager.clone_state(&self.scroll_manager);
 1821        clone.searchable = self.searchable;
 1822        clone.read_only = self.read_only;
 1823        clone
 1824    }
 1825
 1826    pub fn new(
 1827        mode: EditorMode,
 1828        buffer: Entity<MultiBuffer>,
 1829        project: Option<Entity<Project>>,
 1830        window: &mut Window,
 1831        cx: &mut Context<Self>,
 1832    ) -> Self {
 1833        Editor::new_internal(mode, buffer, project, None, window, cx)
 1834    }
 1835
 1836    pub fn sticky_headers(
 1837        &self,
 1838        style: &EditorStyle,
 1839        cx: &App,
 1840    ) -> Option<Vec<OutlineItem<Anchor>>> {
 1841        let multi_buffer = self.buffer().read(cx);
 1842        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1843        let multi_buffer_visible_start = self
 1844            .scroll_manager
 1845            .anchor()
 1846            .anchor
 1847            .to_point(&multi_buffer_snapshot);
 1848        let max_row = multi_buffer_snapshot.max_point().row;
 1849
 1850        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1851        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1852
 1853        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1854            let outline_items = buffer
 1855                .outline_items_containing(
 1856                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1857                    true,
 1858                    Some(style.syntax.as_ref()),
 1859                )
 1860                .into_iter()
 1861                .map(|outline_item| OutlineItem {
 1862                    depth: outline_item.depth,
 1863                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1864                    source_range_for_text: Anchor::range_in_buffer(
 1865                        *excerpt_id,
 1866                        outline_item.source_range_for_text,
 1867                    ),
 1868                    text: outline_item.text,
 1869                    highlight_ranges: outline_item.highlight_ranges,
 1870                    name_ranges: outline_item.name_ranges,
 1871                    body_range: outline_item
 1872                        .body_range
 1873                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1874                    annotation_range: outline_item
 1875                        .annotation_range
 1876                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1877                });
 1878            return Some(outline_items.collect());
 1879        }
 1880
 1881        None
 1882    }
 1883
 1884    fn new_internal(
 1885        mode: EditorMode,
 1886        multi_buffer: Entity<MultiBuffer>,
 1887        project: Option<Entity<Project>>,
 1888        display_map: Option<Entity<DisplayMap>>,
 1889        window: &mut Window,
 1890        cx: &mut Context<Self>,
 1891    ) -> Self {
 1892        debug_assert!(
 1893            display_map.is_none() || mode.is_minimap(),
 1894            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1895        );
 1896
 1897        let full_mode = mode.is_full();
 1898        let is_minimap = mode.is_minimap();
 1899        let diagnostics_max_severity = if full_mode {
 1900            EditorSettings::get_global(cx)
 1901                .diagnostics_max_severity
 1902                .unwrap_or(DiagnosticSeverity::Hint)
 1903        } else {
 1904            DiagnosticSeverity::Off
 1905        };
 1906        let style = window.text_style();
 1907        let font_size = style.font_size.to_pixels(window.rem_size());
 1908        let editor = cx.entity().downgrade();
 1909        let fold_placeholder = FoldPlaceholder {
 1910            constrain_width: false,
 1911            render: Arc::new(move |fold_id, fold_range, cx| {
 1912                let editor = editor.clone();
 1913                div()
 1914                    .id(fold_id)
 1915                    .bg(cx.theme().colors().ghost_element_background)
 1916                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1917                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1918                    .rounded_xs()
 1919                    .size_full()
 1920                    .cursor_pointer()
 1921                    .child("")
 1922                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1923                    .on_click(move |_, _window, cx| {
 1924                        editor
 1925                            .update(cx, |editor, cx| {
 1926                                editor.unfold_ranges(
 1927                                    &[fold_range.start..fold_range.end],
 1928                                    true,
 1929                                    false,
 1930                                    cx,
 1931                                );
 1932                                cx.stop_propagation();
 1933                            })
 1934                            .ok();
 1935                    })
 1936                    .into_any()
 1937            }),
 1938            merge_adjacent: true,
 1939            ..FoldPlaceholder::default()
 1940        };
 1941        let display_map = display_map.unwrap_or_else(|| {
 1942            cx.new(|cx| {
 1943                DisplayMap::new(
 1944                    multi_buffer.clone(),
 1945                    style.font(),
 1946                    font_size,
 1947                    None,
 1948                    FILE_HEADER_HEIGHT,
 1949                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1950                    fold_placeholder,
 1951                    diagnostics_max_severity,
 1952                    cx,
 1953                )
 1954            })
 1955        });
 1956
 1957        let selections = SelectionsCollection::new();
 1958
 1959        let blink_manager = cx.new(|cx| {
 1960            let mut blink_manager = BlinkManager::new(
 1961                CURSOR_BLINK_INTERVAL,
 1962                |cx| EditorSettings::get_global(cx).cursor_blink,
 1963                cx,
 1964            );
 1965            if is_minimap {
 1966                blink_manager.disable(cx);
 1967            }
 1968            blink_manager
 1969        });
 1970
 1971        let soft_wrap_mode_override =
 1972            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1973
 1974        let mut project_subscriptions = Vec::new();
 1975        if full_mode && let Some(project) = project.as_ref() {
 1976            project_subscriptions.push(cx.subscribe_in(
 1977                project,
 1978                window,
 1979                |editor, _, event, window, cx| match event {
 1980                    project::Event::RefreshCodeLens => {
 1981                        // we always query lens with actions, without storing them, always refreshing them
 1982                    }
 1983                    project::Event::RefreshInlayHints {
 1984                        server_id,
 1985                        request_id,
 1986                    } => {
 1987                        editor.refresh_inlay_hints(
 1988                            InlayHintRefreshReason::RefreshRequested {
 1989                                server_id: *server_id,
 1990                                request_id: *request_id,
 1991                            },
 1992                            cx,
 1993                        );
 1994                    }
 1995                    project::Event::LanguageServerRemoved(..) => {
 1996                        if editor.tasks_update_task.is_none() {
 1997                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1998                        }
 1999                        editor.registered_buffers.clear();
 2000                        editor.register_visible_buffers(cx);
 2001                    }
 2002                    project::Event::LanguageServerAdded(..) => {
 2003                        if editor.tasks_update_task.is_none() {
 2004                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2005                        }
 2006                    }
 2007                    project::Event::SnippetEdit(id, snippet_edits) => {
 2008                        // todo(lw): Non singletons
 2009                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2010                            let snapshot = buffer.read(cx).snapshot();
 2011                            let focus_handle = editor.focus_handle(cx);
 2012                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2013                                for (range, snippet) in snippet_edits {
 2014                                    let buffer_range =
 2015                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2016                                    editor
 2017                                        .insert_snippet(
 2018                                            &[MultiBufferOffset(buffer_range.start)
 2019                                                ..MultiBufferOffset(buffer_range.end)],
 2020                                            snippet.clone(),
 2021                                            window,
 2022                                            cx,
 2023                                        )
 2024                                        .ok();
 2025                                }
 2026                            }
 2027                        }
 2028                    }
 2029                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2030                        let buffer_id = *buffer_id;
 2031                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2032                            editor.register_buffer(buffer_id, cx);
 2033                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2034                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2035                            refresh_linked_ranges(editor, window, cx);
 2036                            editor.refresh_code_actions(window, cx);
 2037                            editor.refresh_document_highlights(cx);
 2038                        }
 2039                    }
 2040
 2041                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2042                        let Some(workspace) = editor.workspace() else {
 2043                            return;
 2044                        };
 2045                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2046                        else {
 2047                            return;
 2048                        };
 2049
 2050                        if active_editor.entity_id() == cx.entity_id() {
 2051                            let entity_id = cx.entity_id();
 2052                            workspace.update(cx, |this, cx| {
 2053                                this.panes_mut()
 2054                                    .iter_mut()
 2055                                    .filter(|pane| pane.entity_id() != entity_id)
 2056                                    .for_each(|p| {
 2057                                        p.update(cx, |pane, _| {
 2058                                            pane.nav_history_mut().rename_item(
 2059                                                entity_id,
 2060                                                project_path.clone(),
 2061                                                abs_path.clone().into(),
 2062                                            );
 2063                                        })
 2064                                    });
 2065                            });
 2066
 2067                            Self::open_transaction_for_hidden_buffers(
 2068                                workspace,
 2069                                transaction.clone(),
 2070                                "Rename".to_string(),
 2071                                window,
 2072                                cx,
 2073                            );
 2074                        }
 2075                    }
 2076
 2077                    project::Event::WorkspaceEditApplied(transaction) => {
 2078                        let Some(workspace) = editor.workspace() else {
 2079                            return;
 2080                        };
 2081                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2082                        else {
 2083                            return;
 2084                        };
 2085
 2086                        if active_editor.entity_id() == cx.entity_id() {
 2087                            Self::open_transaction_for_hidden_buffers(
 2088                                workspace,
 2089                                transaction.clone(),
 2090                                "LSP Edit".to_string(),
 2091                                window,
 2092                                cx,
 2093                            );
 2094                        }
 2095                    }
 2096
 2097                    _ => {}
 2098                },
 2099            ));
 2100            if let Some(task_inventory) = project
 2101                .read(cx)
 2102                .task_store()
 2103                .read(cx)
 2104                .task_inventory()
 2105                .cloned()
 2106            {
 2107                project_subscriptions.push(cx.observe_in(
 2108                    &task_inventory,
 2109                    window,
 2110                    |editor, _, window, cx| {
 2111                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2112                    },
 2113                ));
 2114            };
 2115
 2116            project_subscriptions.push(cx.subscribe_in(
 2117                &project.read(cx).breakpoint_store(),
 2118                window,
 2119                |editor, _, event, window, cx| match event {
 2120                    BreakpointStoreEvent::ClearDebugLines => {
 2121                        editor.clear_row_highlights::<ActiveDebugLine>();
 2122                        editor.refresh_inline_values(cx);
 2123                    }
 2124                    BreakpointStoreEvent::SetDebugLine => {
 2125                        if editor.go_to_active_debug_line(window, cx) {
 2126                            cx.stop_propagation();
 2127                        }
 2128
 2129                        editor.refresh_inline_values(cx);
 2130                    }
 2131                    _ => {}
 2132                },
 2133            ));
 2134            let git_store = project.read(cx).git_store().clone();
 2135            let project = project.clone();
 2136            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2137                if let GitStoreEvent::RepositoryAdded = event {
 2138                    this.load_diff_task = Some(
 2139                        update_uncommitted_diff_for_buffer(
 2140                            cx.entity(),
 2141                            &project,
 2142                            this.buffer.read(cx).all_buffers(),
 2143                            this.buffer.clone(),
 2144                            cx,
 2145                        )
 2146                        .shared(),
 2147                    );
 2148                }
 2149            }));
 2150        }
 2151
 2152        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2153
 2154        let inlay_hint_settings =
 2155            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2156        let focus_handle = cx.focus_handle();
 2157        if !is_minimap {
 2158            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2159                .detach();
 2160            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2161                .detach();
 2162            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2163                .detach();
 2164            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2165                .detach();
 2166            cx.observe_pending_input(window, Self::observe_pending_input)
 2167                .detach();
 2168        }
 2169
 2170        let show_indent_guides =
 2171            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2172                Some(false)
 2173            } else {
 2174                None
 2175            };
 2176
 2177        let breakpoint_store = match (&mode, project.as_ref()) {
 2178            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2179            _ => None,
 2180        };
 2181
 2182        let mut code_action_providers = Vec::new();
 2183        let mut load_uncommitted_diff = None;
 2184        if let Some(project) = project.clone() {
 2185            load_uncommitted_diff = Some(
 2186                update_uncommitted_diff_for_buffer(
 2187                    cx.entity(),
 2188                    &project,
 2189                    multi_buffer.read(cx).all_buffers(),
 2190                    multi_buffer.clone(),
 2191                    cx,
 2192                )
 2193                .shared(),
 2194            );
 2195            code_action_providers.push(Rc::new(project) as Rc<_>);
 2196        }
 2197
 2198        let mut editor = Self {
 2199            focus_handle,
 2200            show_cursor_when_unfocused: false,
 2201            last_focused_descendant: None,
 2202            buffer: multi_buffer.clone(),
 2203            display_map: display_map.clone(),
 2204            placeholder_display_map: None,
 2205            selections,
 2206            scroll_manager: ScrollManager::new(cx),
 2207            columnar_selection_state: None,
 2208            add_selections_state: None,
 2209            select_next_state: None,
 2210            select_prev_state: None,
 2211            selection_history: SelectionHistory::default(),
 2212            defer_selection_effects: false,
 2213            deferred_selection_effects_state: None,
 2214            autoclose_regions: Vec::new(),
 2215            snippet_stack: InvalidationStack::default(),
 2216            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2217            ime_transaction: None,
 2218            active_diagnostics: ActiveDiagnostic::None,
 2219            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2220            inline_diagnostics_update: Task::ready(()),
 2221            inline_diagnostics: Vec::new(),
 2222            soft_wrap_mode_override,
 2223            diagnostics_max_severity,
 2224            hard_wrap: None,
 2225            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2226            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2227            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2228            project,
 2229            blink_manager: blink_manager.clone(),
 2230            show_local_selections: true,
 2231            show_scrollbars: ScrollbarAxes {
 2232                horizontal: full_mode,
 2233                vertical: full_mode,
 2234            },
 2235            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2236            offset_content: !matches!(mode, EditorMode::SingleLine),
 2237            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2238            show_gutter: full_mode,
 2239            show_line_numbers: (!full_mode).then_some(false),
 2240            use_relative_line_numbers: None,
 2241            disable_expand_excerpt_buttons: !full_mode,
 2242            delegate_expand_excerpts: false,
 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            number_deleted_lines: 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                        .to_lowercase(),
 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            number_deleted_lines: self.number_deleted_lines,
 2947            show_git_diff_gutter: self.show_git_diff_gutter,
 2948            show_code_actions: self.show_code_actions,
 2949            show_runnables: self.show_runnables,
 2950            show_breakpoints: self.show_breakpoints,
 2951            git_blame_gutter_max_author_length,
 2952            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2953            placeholder_display_snapshot: self
 2954                .placeholder_display_map
 2955                .as_ref()
 2956                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2957            scroll_anchor: self.scroll_manager.anchor(),
 2958            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2959            is_focused: self.focus_handle.is_focused(window),
 2960            current_line_highlight: self
 2961                .current_line_highlight
 2962                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2963            gutter_hovered: self.gutter_hovered,
 2964        }
 2965    }
 2966
 2967    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2968        self.buffer.read(cx).language_at(point, cx)
 2969    }
 2970
 2971    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2972        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2973    }
 2974
 2975    pub fn active_excerpt(
 2976        &self,
 2977        cx: &App,
 2978    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2979        self.buffer
 2980            .read(cx)
 2981            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2982    }
 2983
 2984    pub fn mode(&self) -> &EditorMode {
 2985        &self.mode
 2986    }
 2987
 2988    pub fn set_mode(&mut self, mode: EditorMode) {
 2989        self.mode = mode;
 2990    }
 2991
 2992    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2993        self.collaboration_hub.as_deref()
 2994    }
 2995
 2996    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2997        self.collaboration_hub = Some(hub);
 2998    }
 2999
 3000    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3001        self.in_project_search = in_project_search;
 3002    }
 3003
 3004    pub fn set_custom_context_menu(
 3005        &mut self,
 3006        f: impl 'static
 3007        + Fn(
 3008            &mut Self,
 3009            DisplayPoint,
 3010            &mut Window,
 3011            &mut Context<Self>,
 3012        ) -> Option<Entity<ui::ContextMenu>>,
 3013    ) {
 3014        self.custom_context_menu = Some(Box::new(f))
 3015    }
 3016
 3017    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3018        self.completion_provider = provider;
 3019    }
 3020
 3021    #[cfg(any(test, feature = "test-support"))]
 3022    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3023        self.completion_provider.clone()
 3024    }
 3025
 3026    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3027        self.semantics_provider.clone()
 3028    }
 3029
 3030    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3031        self.semantics_provider = provider;
 3032    }
 3033
 3034    pub fn set_edit_prediction_provider<T>(
 3035        &mut self,
 3036        provider: Option<Entity<T>>,
 3037        window: &mut Window,
 3038        cx: &mut Context<Self>,
 3039    ) where
 3040        T: EditPredictionDelegate,
 3041    {
 3042        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3043            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3044                if this.focus_handle.is_focused(window) {
 3045                    this.update_visible_edit_prediction(window, cx);
 3046                }
 3047            }),
 3048            provider: Arc::new(provider),
 3049        });
 3050        self.update_edit_prediction_settings(cx);
 3051        self.refresh_edit_prediction(false, false, window, cx);
 3052    }
 3053
 3054    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3055        self.placeholder_display_map
 3056            .as_ref()
 3057            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3058    }
 3059
 3060    pub fn set_placeholder_text(
 3061        &mut self,
 3062        placeholder_text: &str,
 3063        window: &mut Window,
 3064        cx: &mut Context<Self>,
 3065    ) {
 3066        let multibuffer = cx
 3067            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3068
 3069        let style = window.text_style();
 3070
 3071        self.placeholder_display_map = Some(cx.new(|cx| {
 3072            DisplayMap::new(
 3073                multibuffer,
 3074                style.font(),
 3075                style.font_size.to_pixels(window.rem_size()),
 3076                None,
 3077                FILE_HEADER_HEIGHT,
 3078                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3079                Default::default(),
 3080                DiagnosticSeverity::Off,
 3081                cx,
 3082            )
 3083        }));
 3084        cx.notify();
 3085    }
 3086
 3087    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3088        self.cursor_shape = cursor_shape;
 3089
 3090        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3091        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3092
 3093        cx.notify();
 3094    }
 3095
 3096    pub fn cursor_shape(&self) -> CursorShape {
 3097        self.cursor_shape
 3098    }
 3099
 3100    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3101        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3102    }
 3103
 3104    pub fn set_current_line_highlight(
 3105        &mut self,
 3106        current_line_highlight: Option<CurrentLineHighlight>,
 3107    ) {
 3108        self.current_line_highlight = current_line_highlight;
 3109    }
 3110
 3111    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3112        self.collapse_matches = collapse_matches;
 3113    }
 3114
 3115    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3116        if self.collapse_matches {
 3117            return range.start..range.start;
 3118        }
 3119        range.clone()
 3120    }
 3121
 3122    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3123        self.display_map.read(cx).clip_at_line_ends
 3124    }
 3125
 3126    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3127        if self.display_map.read(cx).clip_at_line_ends != clip {
 3128            self.display_map
 3129                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3130        }
 3131    }
 3132
 3133    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3134        self.input_enabled = input_enabled;
 3135    }
 3136
 3137    pub fn set_edit_predictions_hidden_for_vim_mode(
 3138        &mut self,
 3139        hidden: bool,
 3140        window: &mut Window,
 3141        cx: &mut Context<Self>,
 3142    ) {
 3143        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3144            self.edit_predictions_hidden_for_vim_mode = hidden;
 3145            if hidden {
 3146                self.update_visible_edit_prediction(window, cx);
 3147            } else {
 3148                self.refresh_edit_prediction(true, false, window, cx);
 3149            }
 3150        }
 3151    }
 3152
 3153    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3154        self.menu_edit_predictions_policy = value;
 3155    }
 3156
 3157    pub fn set_autoindent(&mut self, autoindent: bool) {
 3158        if autoindent {
 3159            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3160        } else {
 3161            self.autoindent_mode = None;
 3162        }
 3163    }
 3164
 3165    pub fn capability(&self, cx: &App) -> Capability {
 3166        if self.read_only {
 3167            Capability::ReadOnly
 3168        } else {
 3169            self.buffer.read(cx).capability()
 3170        }
 3171    }
 3172
 3173    pub fn read_only(&self, cx: &App) -> bool {
 3174        self.read_only || self.buffer.read(cx).read_only()
 3175    }
 3176
 3177    pub fn set_read_only(&mut self, read_only: bool) {
 3178        self.read_only = read_only;
 3179    }
 3180
 3181    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3182        self.use_autoclose = autoclose;
 3183    }
 3184
 3185    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3186        self.use_auto_surround = auto_surround;
 3187    }
 3188
 3189    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3190        self.auto_replace_emoji_shortcode = auto_replace;
 3191    }
 3192
 3193    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3194        self.buffer_serialization = should_serialize.then(|| {
 3195            BufferSerialization::new(
 3196                ProjectSettings::get_global(cx)
 3197                    .session
 3198                    .restore_unsaved_buffers,
 3199            )
 3200        })
 3201    }
 3202
 3203    fn should_serialize_buffer(&self) -> bool {
 3204        self.buffer_serialization.is_some()
 3205    }
 3206
 3207    pub fn toggle_edit_predictions(
 3208        &mut self,
 3209        _: &ToggleEditPrediction,
 3210        window: &mut Window,
 3211        cx: &mut Context<Self>,
 3212    ) {
 3213        if self.show_edit_predictions_override.is_some() {
 3214            self.set_show_edit_predictions(None, window, cx);
 3215        } else {
 3216            let show_edit_predictions = !self.edit_predictions_enabled();
 3217            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3218        }
 3219    }
 3220
 3221    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3222        self.show_completions_on_input_override = show_completions_on_input;
 3223    }
 3224
 3225    pub fn set_show_edit_predictions(
 3226        &mut self,
 3227        show_edit_predictions: Option<bool>,
 3228        window: &mut Window,
 3229        cx: &mut Context<Self>,
 3230    ) {
 3231        self.show_edit_predictions_override = show_edit_predictions;
 3232        self.update_edit_prediction_settings(cx);
 3233
 3234        if let Some(false) = show_edit_predictions {
 3235            self.discard_edit_prediction(false, cx);
 3236        } else {
 3237            self.refresh_edit_prediction(false, true, window, cx);
 3238        }
 3239    }
 3240
 3241    fn edit_predictions_disabled_in_scope(
 3242        &self,
 3243        buffer: &Entity<Buffer>,
 3244        buffer_position: language::Anchor,
 3245        cx: &App,
 3246    ) -> bool {
 3247        let snapshot = buffer.read(cx).snapshot();
 3248        let settings = snapshot.settings_at(buffer_position, cx);
 3249
 3250        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3251            return false;
 3252        };
 3253
 3254        scope.override_name().is_some_and(|scope_name| {
 3255            settings
 3256                .edit_predictions_disabled_in
 3257                .iter()
 3258                .any(|s| s == scope_name)
 3259        })
 3260    }
 3261
 3262    pub fn set_use_modal_editing(&mut self, to: bool) {
 3263        self.use_modal_editing = to;
 3264    }
 3265
 3266    pub fn use_modal_editing(&self) -> bool {
 3267        self.use_modal_editing
 3268    }
 3269
 3270    fn selections_did_change(
 3271        &mut self,
 3272        local: bool,
 3273        old_cursor_position: &Anchor,
 3274        effects: SelectionEffects,
 3275        window: &mut Window,
 3276        cx: &mut Context<Self>,
 3277    ) {
 3278        window.invalidate_character_coordinates();
 3279
 3280        // Copy selections to primary selection buffer
 3281        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3282        if local {
 3283            let selections = self
 3284                .selections
 3285                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3286            let buffer_handle = self.buffer.read(cx).read(cx);
 3287
 3288            let mut text = String::new();
 3289            for (index, selection) in selections.iter().enumerate() {
 3290                let text_for_selection = buffer_handle
 3291                    .text_for_range(selection.start..selection.end)
 3292                    .collect::<String>();
 3293
 3294                text.push_str(&text_for_selection);
 3295                if index != selections.len() - 1 {
 3296                    text.push('\n');
 3297                }
 3298            }
 3299
 3300            if !text.is_empty() {
 3301                cx.write_to_primary(ClipboardItem::new_string(text));
 3302            }
 3303        }
 3304
 3305        let selection_anchors = self.selections.disjoint_anchors_arc();
 3306
 3307        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3308            self.buffer.update(cx, |buffer, cx| {
 3309                buffer.set_active_selections(
 3310                    &selection_anchors,
 3311                    self.selections.line_mode(),
 3312                    self.cursor_shape,
 3313                    cx,
 3314                )
 3315            });
 3316        }
 3317        let display_map = self
 3318            .display_map
 3319            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3320        let buffer = display_map.buffer_snapshot();
 3321        if self.selections.count() == 1 {
 3322            self.add_selections_state = None;
 3323        }
 3324        self.select_next_state = None;
 3325        self.select_prev_state = None;
 3326        self.select_syntax_node_history.try_clear();
 3327        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3328        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3329        self.take_rename(false, window, cx);
 3330
 3331        let newest_selection = self.selections.newest_anchor();
 3332        let new_cursor_position = newest_selection.head();
 3333        let selection_start = newest_selection.start;
 3334
 3335        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3336            self.push_to_nav_history(
 3337                *old_cursor_position,
 3338                Some(new_cursor_position.to_point(buffer)),
 3339                false,
 3340                effects.nav_history == Some(true),
 3341                cx,
 3342            );
 3343        }
 3344
 3345        if local {
 3346            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3347                self.register_buffer(buffer_id, cx);
 3348            }
 3349
 3350            let mut context_menu = self.context_menu.borrow_mut();
 3351            let completion_menu = match context_menu.as_ref() {
 3352                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3353                Some(CodeContextMenu::CodeActions(_)) => {
 3354                    *context_menu = None;
 3355                    None
 3356                }
 3357                None => None,
 3358            };
 3359            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3360            drop(context_menu);
 3361
 3362            if effects.completions
 3363                && let Some(completion_position) = completion_position
 3364            {
 3365                let start_offset = selection_start.to_offset(buffer);
 3366                let position_matches = start_offset == completion_position.to_offset(buffer);
 3367                let continue_showing = if let Some((snap, ..)) =
 3368                    buffer.point_to_buffer_offset(completion_position)
 3369                    && !snap.capability.editable()
 3370                {
 3371                    false
 3372                } else if position_matches {
 3373                    if self.snippet_stack.is_empty() {
 3374                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3375                            == Some(CharKind::Word)
 3376                    } else {
 3377                        // Snippet choices can be shown even when the cursor is in whitespace.
 3378                        // Dismissing the menu with actions like backspace is handled by
 3379                        // invalidation regions.
 3380                        true
 3381                    }
 3382                } else {
 3383                    false
 3384                };
 3385
 3386                if continue_showing {
 3387                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3388                } else {
 3389                    self.hide_context_menu(window, cx);
 3390                }
 3391            }
 3392
 3393            hide_hover(self, cx);
 3394
 3395            if old_cursor_position.to_display_point(&display_map).row()
 3396                != new_cursor_position.to_display_point(&display_map).row()
 3397            {
 3398                self.available_code_actions.take();
 3399            }
 3400            self.refresh_code_actions(window, cx);
 3401            self.refresh_document_highlights(cx);
 3402            refresh_linked_ranges(self, window, cx);
 3403
 3404            self.refresh_selected_text_highlights(false, window, cx);
 3405            self.refresh_matching_bracket_highlights(window, cx);
 3406            self.update_visible_edit_prediction(window, cx);
 3407            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3408            self.inline_blame_popover.take();
 3409            if self.git_blame_inline_enabled {
 3410                self.start_inline_blame_timer(window, cx);
 3411            }
 3412        }
 3413
 3414        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3415        cx.emit(EditorEvent::SelectionsChanged { local });
 3416
 3417        let selections = &self.selections.disjoint_anchors_arc();
 3418        if selections.len() == 1 {
 3419            cx.emit(SearchEvent::ActiveMatchChanged)
 3420        }
 3421        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3422            let inmemory_selections = selections
 3423                .iter()
 3424                .map(|s| {
 3425                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3426                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3427                })
 3428                .collect();
 3429            self.update_restoration_data(cx, |data| {
 3430                data.selections = inmemory_selections;
 3431            });
 3432
 3433            if WorkspaceSettings::get(None, cx).restore_on_startup
 3434                != RestoreOnStartupBehavior::EmptyTab
 3435                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3436            {
 3437                let snapshot = self.buffer().read(cx).snapshot(cx);
 3438                let selections = selections.clone();
 3439                let background_executor = cx.background_executor().clone();
 3440                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3441                self.serialize_selections = cx.background_spawn(async move {
 3442                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3443                    let db_selections = selections
 3444                        .iter()
 3445                        .map(|selection| {
 3446                            (
 3447                                selection.start.to_offset(&snapshot).0,
 3448                                selection.end.to_offset(&snapshot).0,
 3449                            )
 3450                        })
 3451                        .collect();
 3452
 3453                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3454                        .await
 3455                        .with_context(|| {
 3456                            format!(
 3457                                "persisting editor selections for editor {editor_id}, \
 3458                                workspace {workspace_id:?}"
 3459                            )
 3460                        })
 3461                        .log_err();
 3462                });
 3463            }
 3464        }
 3465
 3466        cx.notify();
 3467    }
 3468
 3469    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3470        use text::ToOffset as _;
 3471        use text::ToPoint as _;
 3472
 3473        if self.mode.is_minimap()
 3474            || WorkspaceSettings::get(None, cx).restore_on_startup
 3475                == RestoreOnStartupBehavior::EmptyTab
 3476        {
 3477            return;
 3478        }
 3479
 3480        if !self.buffer().read(cx).is_singleton() {
 3481            return;
 3482        }
 3483
 3484        let display_snapshot = self
 3485            .display_map
 3486            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3487        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3488            return;
 3489        };
 3490        let inmemory_folds = display_snapshot
 3491            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3492            .map(|fold| {
 3493                fold.range.start.text_anchor.to_point(&snapshot)
 3494                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3495            })
 3496            .collect();
 3497        self.update_restoration_data(cx, |data| {
 3498            data.folds = inmemory_folds;
 3499        });
 3500
 3501        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3502            return;
 3503        };
 3504        let background_executor = cx.background_executor().clone();
 3505        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3506        let db_folds = display_snapshot
 3507            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3508            .map(|fold| {
 3509                (
 3510                    fold.range.start.text_anchor.to_offset(&snapshot),
 3511                    fold.range.end.text_anchor.to_offset(&snapshot),
 3512                )
 3513            })
 3514            .collect();
 3515        self.serialize_folds = cx.background_spawn(async move {
 3516            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3517            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3518                .await
 3519                .with_context(|| {
 3520                    format!(
 3521                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3522                    )
 3523                })
 3524                .log_err();
 3525        });
 3526    }
 3527
 3528    pub fn sync_selections(
 3529        &mut self,
 3530        other: Entity<Editor>,
 3531        cx: &mut Context<Self>,
 3532    ) -> gpui::Subscription {
 3533        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3534        if !other_selections.is_empty() {
 3535            self.selections
 3536                .change_with(&self.display_snapshot(cx), |selections| {
 3537                    selections.select_anchors(other_selections);
 3538                });
 3539        }
 3540
 3541        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3542            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3543                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3544                if other_selections.is_empty() {
 3545                    return;
 3546                }
 3547                let snapshot = this.display_snapshot(cx);
 3548                this.selections.change_with(&snapshot, |selections| {
 3549                    selections.select_anchors(other_selections);
 3550                });
 3551            }
 3552        });
 3553
 3554        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3555            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3556                let these_selections = this.selections.disjoint_anchors().to_vec();
 3557                if these_selections.is_empty() {
 3558                    return;
 3559                }
 3560                other.update(cx, |other_editor, cx| {
 3561                    let snapshot = other_editor.display_snapshot(cx);
 3562                    other_editor
 3563                        .selections
 3564                        .change_with(&snapshot, |selections| {
 3565                            selections.select_anchors(these_selections);
 3566                        })
 3567                });
 3568            }
 3569        });
 3570
 3571        Subscription::join(other_subscription, this_subscription)
 3572    }
 3573
 3574    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3575        if self.buffer().read(cx).is_singleton() {
 3576            return;
 3577        }
 3578        let snapshot = self.buffer.read(cx).snapshot(cx);
 3579        let buffer_ids: HashSet<BufferId> = self
 3580            .selections
 3581            .disjoint_anchor_ranges()
 3582            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3583            .collect();
 3584        for buffer_id in buffer_ids {
 3585            self.unfold_buffer(buffer_id, cx);
 3586        }
 3587    }
 3588
 3589    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3590    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3591    /// effects of selection change occur at the end of the transaction.
 3592    pub fn change_selections<R>(
 3593        &mut self,
 3594        effects: SelectionEffects,
 3595        window: &mut Window,
 3596        cx: &mut Context<Self>,
 3597        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3598    ) -> R {
 3599        let snapshot = self.display_snapshot(cx);
 3600        if let Some(state) = &mut self.deferred_selection_effects_state {
 3601            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3602            state.effects.completions = effects.completions;
 3603            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3604            let (changed, result) = self.selections.change_with(&snapshot, change);
 3605            state.changed |= changed;
 3606            return result;
 3607        }
 3608        let mut state = DeferredSelectionEffectsState {
 3609            changed: false,
 3610            effects,
 3611            old_cursor_position: self.selections.newest_anchor().head(),
 3612            history_entry: SelectionHistoryEntry {
 3613                selections: self.selections.disjoint_anchors_arc(),
 3614                select_next_state: self.select_next_state.clone(),
 3615                select_prev_state: self.select_prev_state.clone(),
 3616                add_selections_state: self.add_selections_state.clone(),
 3617            },
 3618        };
 3619        let (changed, result) = self.selections.change_with(&snapshot, change);
 3620        state.changed = state.changed || changed;
 3621        if self.defer_selection_effects {
 3622            self.deferred_selection_effects_state = Some(state);
 3623        } else {
 3624            self.apply_selection_effects(state, window, cx);
 3625        }
 3626        result
 3627    }
 3628
 3629    /// Defers the effects of selection change, so that the effects of multiple calls to
 3630    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3631    /// to selection history and the state of popovers based on selection position aren't
 3632    /// erroneously updated.
 3633    pub fn with_selection_effects_deferred<R>(
 3634        &mut self,
 3635        window: &mut Window,
 3636        cx: &mut Context<Self>,
 3637        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3638    ) -> R {
 3639        let already_deferred = self.defer_selection_effects;
 3640        self.defer_selection_effects = true;
 3641        let result = update(self, window, cx);
 3642        if !already_deferred {
 3643            self.defer_selection_effects = false;
 3644            if let Some(state) = self.deferred_selection_effects_state.take() {
 3645                self.apply_selection_effects(state, window, cx);
 3646            }
 3647        }
 3648        result
 3649    }
 3650
 3651    fn apply_selection_effects(
 3652        &mut self,
 3653        state: DeferredSelectionEffectsState,
 3654        window: &mut Window,
 3655        cx: &mut Context<Self>,
 3656    ) {
 3657        if state.changed {
 3658            self.selection_history.push(state.history_entry);
 3659
 3660            if let Some(autoscroll) = state.effects.scroll {
 3661                self.request_autoscroll(autoscroll, cx);
 3662            }
 3663
 3664            let old_cursor_position = &state.old_cursor_position;
 3665
 3666            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3667
 3668            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3669                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3670            }
 3671        }
 3672    }
 3673
 3674    pub fn edit<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
 3685            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3686    }
 3687
 3688    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3689    where
 3690        I: IntoIterator<Item = (Range<S>, T)>,
 3691        S: ToOffset,
 3692        T: Into<Arc<str>>,
 3693    {
 3694        if self.read_only(cx) {
 3695            return;
 3696        }
 3697
 3698        self.buffer.update(cx, |buffer, cx| {
 3699            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3700        });
 3701    }
 3702
 3703    pub fn edit_with_block_indent<I, S, T>(
 3704        &mut self,
 3705        edits: I,
 3706        original_indent_columns: Vec<Option<u32>>,
 3707        cx: &mut Context<Self>,
 3708    ) where
 3709        I: IntoIterator<Item = (Range<S>, T)>,
 3710        S: ToOffset,
 3711        T: Into<Arc<str>>,
 3712    {
 3713        if self.read_only(cx) {
 3714            return;
 3715        }
 3716
 3717        self.buffer.update(cx, |buffer, cx| {
 3718            buffer.edit(
 3719                edits,
 3720                Some(AutoindentMode::Block {
 3721                    original_indent_columns,
 3722                }),
 3723                cx,
 3724            )
 3725        });
 3726    }
 3727
 3728    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3729        self.hide_context_menu(window, cx);
 3730
 3731        match phase {
 3732            SelectPhase::Begin {
 3733                position,
 3734                add,
 3735                click_count,
 3736            } => self.begin_selection(position, add, click_count, window, cx),
 3737            SelectPhase::BeginColumnar {
 3738                position,
 3739                goal_column,
 3740                reset,
 3741                mode,
 3742            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3743            SelectPhase::Extend {
 3744                position,
 3745                click_count,
 3746            } => self.extend_selection(position, click_count, window, cx),
 3747            SelectPhase::Update {
 3748                position,
 3749                goal_column,
 3750                scroll_delta,
 3751            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3752            SelectPhase::End => self.end_selection(window, cx),
 3753        }
 3754    }
 3755
 3756    fn extend_selection(
 3757        &mut self,
 3758        position: DisplayPoint,
 3759        click_count: usize,
 3760        window: &mut Window,
 3761        cx: &mut Context<Self>,
 3762    ) {
 3763        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3764        let tail = self
 3765            .selections
 3766            .newest::<MultiBufferOffset>(&display_map)
 3767            .tail();
 3768        let click_count = click_count.max(match self.selections.select_mode() {
 3769            SelectMode::Character => 1,
 3770            SelectMode::Word(_) => 2,
 3771            SelectMode::Line(_) => 3,
 3772            SelectMode::All => 4,
 3773        });
 3774        self.begin_selection(position, false, click_count, window, cx);
 3775
 3776        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3777
 3778        let current_selection = match self.selections.select_mode() {
 3779            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3780            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3781        };
 3782
 3783        let mut pending_selection = self
 3784            .selections
 3785            .pending_anchor()
 3786            .cloned()
 3787            .expect("extend_selection not called with pending selection");
 3788
 3789        if pending_selection
 3790            .start
 3791            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3792            == Ordering::Greater
 3793        {
 3794            pending_selection.start = current_selection.start;
 3795        }
 3796        if pending_selection
 3797            .end
 3798            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3799            == Ordering::Less
 3800        {
 3801            pending_selection.end = current_selection.end;
 3802            pending_selection.reversed = true;
 3803        }
 3804
 3805        let mut pending_mode = self.selections.pending_mode().unwrap();
 3806        match &mut pending_mode {
 3807            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3808            _ => {}
 3809        }
 3810
 3811        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3812            SelectionEffects::scroll(Autoscroll::fit())
 3813        } else {
 3814            SelectionEffects::no_scroll()
 3815        };
 3816
 3817        self.change_selections(effects, window, cx, |s| {
 3818            s.set_pending(pending_selection.clone(), pending_mode);
 3819            s.set_is_extending(true);
 3820        });
 3821    }
 3822
 3823    fn begin_selection(
 3824        &mut self,
 3825        position: DisplayPoint,
 3826        add: bool,
 3827        click_count: usize,
 3828        window: &mut Window,
 3829        cx: &mut Context<Self>,
 3830    ) {
 3831        if !self.focus_handle.is_focused(window) {
 3832            self.last_focused_descendant = None;
 3833            window.focus(&self.focus_handle, cx);
 3834        }
 3835
 3836        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3837        let buffer = display_map.buffer_snapshot();
 3838        let position = display_map.clip_point(position, Bias::Left);
 3839
 3840        let start;
 3841        let end;
 3842        let mode;
 3843        let mut auto_scroll;
 3844        match click_count {
 3845            1 => {
 3846                start = buffer.anchor_before(position.to_point(&display_map));
 3847                end = start;
 3848                mode = SelectMode::Character;
 3849                auto_scroll = true;
 3850            }
 3851            2 => {
 3852                let position = display_map
 3853                    .clip_point(position, Bias::Left)
 3854                    .to_offset(&display_map, Bias::Left);
 3855                let (range, _) = buffer.surrounding_word(position, None);
 3856                start = buffer.anchor_before(range.start);
 3857                end = buffer.anchor_before(range.end);
 3858                mode = SelectMode::Word(start..end);
 3859                auto_scroll = true;
 3860            }
 3861            3 => {
 3862                let position = display_map
 3863                    .clip_point(position, Bias::Left)
 3864                    .to_point(&display_map);
 3865                let line_start = display_map.prev_line_boundary(position).0;
 3866                let next_line_start = buffer.clip_point(
 3867                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3868                    Bias::Left,
 3869                );
 3870                start = buffer.anchor_before(line_start);
 3871                end = buffer.anchor_before(next_line_start);
 3872                mode = SelectMode::Line(start..end);
 3873                auto_scroll = true;
 3874            }
 3875            _ => {
 3876                start = buffer.anchor_before(MultiBufferOffset(0));
 3877                end = buffer.anchor_before(buffer.len());
 3878                mode = SelectMode::All;
 3879                auto_scroll = false;
 3880            }
 3881        }
 3882        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3883
 3884        let point_to_delete: Option<usize> = {
 3885            let selected_points: Vec<Selection<Point>> =
 3886                self.selections.disjoint_in_range(start..end, &display_map);
 3887
 3888            if !add || click_count > 1 {
 3889                None
 3890            } else if !selected_points.is_empty() {
 3891                Some(selected_points[0].id)
 3892            } else {
 3893                let clicked_point_already_selected =
 3894                    self.selections.disjoint_anchors().iter().find(|selection| {
 3895                        selection.start.to_point(buffer) == start.to_point(buffer)
 3896                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3897                    });
 3898
 3899                clicked_point_already_selected.map(|selection| selection.id)
 3900            }
 3901        };
 3902
 3903        let selections_count = self.selections.count();
 3904        let effects = if auto_scroll {
 3905            SelectionEffects::default()
 3906        } else {
 3907            SelectionEffects::no_scroll()
 3908        };
 3909
 3910        self.change_selections(effects, window, cx, |s| {
 3911            if let Some(point_to_delete) = point_to_delete {
 3912                s.delete(point_to_delete);
 3913
 3914                if selections_count == 1 {
 3915                    s.set_pending_anchor_range(start..end, mode);
 3916                }
 3917            } else {
 3918                if !add {
 3919                    s.clear_disjoint();
 3920                }
 3921
 3922                s.set_pending_anchor_range(start..end, mode);
 3923            }
 3924        });
 3925    }
 3926
 3927    fn begin_columnar_selection(
 3928        &mut self,
 3929        position: DisplayPoint,
 3930        goal_column: u32,
 3931        reset: bool,
 3932        mode: ColumnarMode,
 3933        window: &mut Window,
 3934        cx: &mut Context<Self>,
 3935    ) {
 3936        if !self.focus_handle.is_focused(window) {
 3937            self.last_focused_descendant = None;
 3938            window.focus(&self.focus_handle, cx);
 3939        }
 3940
 3941        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3942
 3943        if reset {
 3944            let pointer_position = display_map
 3945                .buffer_snapshot()
 3946                .anchor_before(position.to_point(&display_map));
 3947
 3948            self.change_selections(
 3949                SelectionEffects::scroll(Autoscroll::newest()),
 3950                window,
 3951                cx,
 3952                |s| {
 3953                    s.clear_disjoint();
 3954                    s.set_pending_anchor_range(
 3955                        pointer_position..pointer_position,
 3956                        SelectMode::Character,
 3957                    );
 3958                },
 3959            );
 3960        };
 3961
 3962        let tail = self.selections.newest::<Point>(&display_map).tail();
 3963        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3964        self.columnar_selection_state = match mode {
 3965            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3966                selection_tail: selection_anchor,
 3967                display_point: if reset {
 3968                    if position.column() != goal_column {
 3969                        Some(DisplayPoint::new(position.row(), goal_column))
 3970                    } else {
 3971                        None
 3972                    }
 3973                } else {
 3974                    None
 3975                },
 3976            }),
 3977            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3978                selection_tail: selection_anchor,
 3979            }),
 3980        };
 3981
 3982        if !reset {
 3983            self.select_columns(position, goal_column, &display_map, window, cx);
 3984        }
 3985    }
 3986
 3987    fn update_selection(
 3988        &mut self,
 3989        position: DisplayPoint,
 3990        goal_column: u32,
 3991        scroll_delta: gpui::Point<f32>,
 3992        window: &mut Window,
 3993        cx: &mut Context<Self>,
 3994    ) {
 3995        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3996
 3997        if self.columnar_selection_state.is_some() {
 3998            self.select_columns(position, goal_column, &display_map, window, cx);
 3999        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 4000            let buffer = display_map.buffer_snapshot();
 4001            let head;
 4002            let tail;
 4003            let mode = self.selections.pending_mode().unwrap();
 4004            match &mode {
 4005                SelectMode::Character => {
 4006                    head = position.to_point(&display_map);
 4007                    tail = pending.tail().to_point(buffer);
 4008                }
 4009                SelectMode::Word(original_range) => {
 4010                    let offset = display_map
 4011                        .clip_point(position, Bias::Left)
 4012                        .to_offset(&display_map, Bias::Left);
 4013                    let original_range = original_range.to_offset(buffer);
 4014
 4015                    let head_offset = if buffer.is_inside_word(offset, None)
 4016                        || original_range.contains(&offset)
 4017                    {
 4018                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4019                        if word_range.start < original_range.start {
 4020                            word_range.start
 4021                        } else {
 4022                            word_range.end
 4023                        }
 4024                    } else {
 4025                        offset
 4026                    };
 4027
 4028                    head = head_offset.to_point(buffer);
 4029                    if head_offset <= original_range.start {
 4030                        tail = original_range.end.to_point(buffer);
 4031                    } else {
 4032                        tail = original_range.start.to_point(buffer);
 4033                    }
 4034                }
 4035                SelectMode::Line(original_range) => {
 4036                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4037
 4038                    let position = display_map
 4039                        .clip_point(position, Bias::Left)
 4040                        .to_point(&display_map);
 4041                    let line_start = display_map.prev_line_boundary(position).0;
 4042                    let next_line_start = buffer.clip_point(
 4043                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4044                        Bias::Left,
 4045                    );
 4046
 4047                    if line_start < original_range.start {
 4048                        head = line_start
 4049                    } else {
 4050                        head = next_line_start
 4051                    }
 4052
 4053                    if head <= original_range.start {
 4054                        tail = original_range.end;
 4055                    } else {
 4056                        tail = original_range.start;
 4057                    }
 4058                }
 4059                SelectMode::All => {
 4060                    return;
 4061                }
 4062            };
 4063
 4064            if head < tail {
 4065                pending.start = buffer.anchor_before(head);
 4066                pending.end = buffer.anchor_before(tail);
 4067                pending.reversed = true;
 4068            } else {
 4069                pending.start = buffer.anchor_before(tail);
 4070                pending.end = buffer.anchor_before(head);
 4071                pending.reversed = false;
 4072            }
 4073
 4074            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4075                s.set_pending(pending.clone(), mode);
 4076            });
 4077        } else {
 4078            log::error!("update_selection dispatched with no pending selection");
 4079            return;
 4080        }
 4081
 4082        self.apply_scroll_delta(scroll_delta, window, cx);
 4083        cx.notify();
 4084    }
 4085
 4086    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4087        self.columnar_selection_state.take();
 4088        if let Some(pending_mode) = self.selections.pending_mode() {
 4089            let selections = self
 4090                .selections
 4091                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4092            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4093                s.select(selections);
 4094                s.clear_pending();
 4095                if s.is_extending() {
 4096                    s.set_is_extending(false);
 4097                } else {
 4098                    s.set_select_mode(pending_mode);
 4099                }
 4100            });
 4101        }
 4102    }
 4103
 4104    fn select_columns(
 4105        &mut self,
 4106        head: DisplayPoint,
 4107        goal_column: u32,
 4108        display_map: &DisplaySnapshot,
 4109        window: &mut Window,
 4110        cx: &mut Context<Self>,
 4111    ) {
 4112        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4113            return;
 4114        };
 4115
 4116        let tail = match columnar_state {
 4117            ColumnarSelectionState::FromMouse {
 4118                selection_tail,
 4119                display_point,
 4120            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4121            ColumnarSelectionState::FromSelection { selection_tail } => {
 4122                selection_tail.to_display_point(display_map)
 4123            }
 4124        };
 4125
 4126        let start_row = cmp::min(tail.row(), head.row());
 4127        let end_row = cmp::max(tail.row(), head.row());
 4128        let start_column = cmp::min(tail.column(), goal_column);
 4129        let end_column = cmp::max(tail.column(), goal_column);
 4130        let reversed = start_column < tail.column();
 4131
 4132        let selection_ranges = (start_row.0..=end_row.0)
 4133            .map(DisplayRow)
 4134            .filter_map(|row| {
 4135                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4136                    || start_column <= display_map.line_len(row))
 4137                    && !display_map.is_block_line(row)
 4138                {
 4139                    let start = display_map
 4140                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4141                        .to_point(display_map);
 4142                    let end = display_map
 4143                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4144                        .to_point(display_map);
 4145                    if reversed {
 4146                        Some(end..start)
 4147                    } else {
 4148                        Some(start..end)
 4149                    }
 4150                } else {
 4151                    None
 4152                }
 4153            })
 4154            .collect::<Vec<_>>();
 4155        if selection_ranges.is_empty() {
 4156            return;
 4157        }
 4158
 4159        let ranges = match columnar_state {
 4160            ColumnarSelectionState::FromMouse { .. } => {
 4161                let mut non_empty_ranges = selection_ranges
 4162                    .iter()
 4163                    .filter(|selection_range| selection_range.start != selection_range.end)
 4164                    .peekable();
 4165                if non_empty_ranges.peek().is_some() {
 4166                    non_empty_ranges.cloned().collect()
 4167                } else {
 4168                    selection_ranges
 4169                }
 4170            }
 4171            _ => selection_ranges,
 4172        };
 4173
 4174        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4175            s.select_ranges(ranges);
 4176        });
 4177        cx.notify();
 4178    }
 4179
 4180    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4181        self.selections
 4182            .all_adjusted(snapshot)
 4183            .iter()
 4184            .any(|selection| !selection.is_empty())
 4185    }
 4186
 4187    pub fn has_pending_nonempty_selection(&self) -> bool {
 4188        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4189            Some(Selection { start, end, .. }) => start != end,
 4190            None => false,
 4191        };
 4192
 4193        pending_nonempty_selection
 4194            || (self.columnar_selection_state.is_some()
 4195                && self.selections.disjoint_anchors().len() > 1)
 4196    }
 4197
 4198    pub fn has_pending_selection(&self) -> bool {
 4199        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4200    }
 4201
 4202    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4203        self.selection_mark_mode = false;
 4204        self.selection_drag_state = SelectionDragState::None;
 4205
 4206        if self.dismiss_menus_and_popups(true, window, cx) {
 4207            cx.notify();
 4208            return;
 4209        }
 4210        if self.clear_expanded_diff_hunks(cx) {
 4211            cx.notify();
 4212            return;
 4213        }
 4214        if self.show_git_blame_gutter {
 4215            self.show_git_blame_gutter = false;
 4216            cx.notify();
 4217            return;
 4218        }
 4219
 4220        if self.mode.is_full()
 4221            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4222        {
 4223            cx.notify();
 4224            return;
 4225        }
 4226
 4227        cx.propagate();
 4228    }
 4229
 4230    pub fn dismiss_menus_and_popups(
 4231        &mut self,
 4232        is_user_requested: bool,
 4233        window: &mut Window,
 4234        cx: &mut Context<Self>,
 4235    ) -> bool {
 4236        let mut dismissed = false;
 4237
 4238        dismissed |= self.take_rename(false, window, cx).is_some();
 4239        dismissed |= self.hide_blame_popover(true, cx);
 4240        dismissed |= hide_hover(self, cx);
 4241        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4242        dismissed |= self.hide_context_menu(window, cx).is_some();
 4243        dismissed |= self.mouse_context_menu.take().is_some();
 4244        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4245        dismissed |= self.snippet_stack.pop().is_some();
 4246
 4247        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4248            self.dismiss_diagnostics(cx);
 4249            dismissed = true;
 4250        }
 4251
 4252        dismissed
 4253    }
 4254
 4255    fn linked_editing_ranges_for(
 4256        &self,
 4257        selection: Range<text::Anchor>,
 4258        cx: &App,
 4259    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4260        if self.linked_edit_ranges.is_empty() {
 4261            return None;
 4262        }
 4263        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4264            selection.end.buffer_id.and_then(|end_buffer_id| {
 4265                if selection.start.buffer_id != Some(end_buffer_id) {
 4266                    return None;
 4267                }
 4268                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4269                let snapshot = buffer.read(cx).snapshot();
 4270                self.linked_edit_ranges
 4271                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4272                    .map(|ranges| (ranges, snapshot, buffer))
 4273            })?;
 4274        use text::ToOffset as TO;
 4275        // find offset from the start of current range to current cursor position
 4276        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4277
 4278        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4279        let start_difference = start_offset - start_byte_offset;
 4280        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4281        let end_difference = end_offset - start_byte_offset;
 4282        // Current range has associated linked ranges.
 4283        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4284        for range in linked_ranges.iter() {
 4285            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4286            let end_offset = start_offset + end_difference;
 4287            let start_offset = start_offset + start_difference;
 4288            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4289                continue;
 4290            }
 4291            if self.selections.disjoint_anchor_ranges().any(|s| {
 4292                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4293                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4294                {
 4295                    return false;
 4296                }
 4297                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4298                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4299            }) {
 4300                continue;
 4301            }
 4302            let start = buffer_snapshot.anchor_after(start_offset);
 4303            let end = buffer_snapshot.anchor_after(end_offset);
 4304            linked_edits
 4305                .entry(buffer.clone())
 4306                .or_default()
 4307                .push(start..end);
 4308        }
 4309        Some(linked_edits)
 4310    }
 4311
 4312    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4313        let text: Arc<str> = text.into();
 4314
 4315        if self.read_only(cx) {
 4316            return;
 4317        }
 4318
 4319        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4320
 4321        self.unfold_buffers_with_selections(cx);
 4322
 4323        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4324        let mut bracket_inserted = false;
 4325        let mut edits = Vec::new();
 4326        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4327        let mut new_selections = Vec::with_capacity(selections.len());
 4328        let mut new_autoclose_regions = Vec::new();
 4329        let snapshot = self.buffer.read(cx).read(cx);
 4330        let mut clear_linked_edit_ranges = false;
 4331        let mut all_selections_read_only = true;
 4332        let mut has_adjacent_edits = false;
 4333        let mut in_adjacent_group = false;
 4334
 4335        let mut regions = self
 4336            .selections_with_autoclose_regions(selections, &snapshot)
 4337            .peekable();
 4338
 4339        while let Some((selection, autoclose_region)) = regions.next() {
 4340            if snapshot
 4341                .point_to_buffer_point(selection.head())
 4342                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4343            {
 4344                continue;
 4345            }
 4346            if snapshot
 4347                .point_to_buffer_point(selection.tail())
 4348                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4349            {
 4350                // note, ideally we'd clip the tail to the closest writeable region towards the head
 4351                continue;
 4352            }
 4353            all_selections_read_only = false;
 4354
 4355            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4356                // Determine if the inserted text matches the opening or closing
 4357                // bracket of any of this language's bracket pairs.
 4358                let mut bracket_pair = None;
 4359                let mut is_bracket_pair_start = false;
 4360                let mut is_bracket_pair_end = false;
 4361                if !text.is_empty() {
 4362                    let mut bracket_pair_matching_end = None;
 4363                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4364                    //  and they are removing the character that triggered IME popup.
 4365                    for (pair, enabled) in scope.brackets() {
 4366                        if !pair.close && !pair.surround {
 4367                            continue;
 4368                        }
 4369
 4370                        if enabled && pair.start.ends_with(text.as_ref()) {
 4371                            let prefix_len = pair.start.len() - text.len();
 4372                            let preceding_text_matches_prefix = prefix_len == 0
 4373                                || (selection.start.column >= (prefix_len as u32)
 4374                                    && snapshot.contains_str_at(
 4375                                        Point::new(
 4376                                            selection.start.row,
 4377                                            selection.start.column - (prefix_len as u32),
 4378                                        ),
 4379                                        &pair.start[..prefix_len],
 4380                                    ));
 4381                            if preceding_text_matches_prefix {
 4382                                bracket_pair = Some(pair.clone());
 4383                                is_bracket_pair_start = true;
 4384                                break;
 4385                            }
 4386                        }
 4387                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4388                        {
 4389                            // take first bracket pair matching end, but don't break in case a later bracket
 4390                            // pair matches start
 4391                            bracket_pair_matching_end = Some(pair.clone());
 4392                        }
 4393                    }
 4394                    if let Some(end) = bracket_pair_matching_end
 4395                        && bracket_pair.is_none()
 4396                    {
 4397                        bracket_pair = Some(end);
 4398                        is_bracket_pair_end = true;
 4399                    }
 4400                }
 4401
 4402                if let Some(bracket_pair) = bracket_pair {
 4403                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4404                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4405                    let auto_surround =
 4406                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4407                    if selection.is_empty() {
 4408                        if is_bracket_pair_start {
 4409                            // If the inserted text is a suffix of an opening bracket and the
 4410                            // selection is preceded by the rest of the opening bracket, then
 4411                            // insert the closing bracket.
 4412                            let following_text_allows_autoclose = snapshot
 4413                                .chars_at(selection.start)
 4414                                .next()
 4415                                .is_none_or(|c| scope.should_autoclose_before(c));
 4416
 4417                            let preceding_text_allows_autoclose = selection.start.column == 0
 4418                                || snapshot
 4419                                    .reversed_chars_at(selection.start)
 4420                                    .next()
 4421                                    .is_none_or(|c| {
 4422                                        bracket_pair.start != bracket_pair.end
 4423                                            || !snapshot
 4424                                                .char_classifier_at(selection.start)
 4425                                                .is_word(c)
 4426                                    });
 4427
 4428                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4429                                && bracket_pair.start.len() == 1
 4430                            {
 4431                                let target = bracket_pair.start.chars().next().unwrap();
 4432                                let mut byte_offset = 0u32;
 4433                                let current_line_count = snapshot
 4434                                    .reversed_chars_at(selection.start)
 4435                                    .take_while(|&c| c != '\n')
 4436                                    .filter(|c| {
 4437                                        byte_offset += c.len_utf8() as u32;
 4438                                        if *c != target {
 4439                                            return false;
 4440                                        }
 4441
 4442                                        let point = Point::new(
 4443                                            selection.start.row,
 4444                                            selection.start.column.saturating_sub(byte_offset),
 4445                                        );
 4446
 4447                                        let is_enabled = snapshot
 4448                                            .language_scope_at(point)
 4449                                            .and_then(|scope| {
 4450                                                scope
 4451                                                    .brackets()
 4452                                                    .find(|(pair, _)| {
 4453                                                        pair.start == bracket_pair.start
 4454                                                    })
 4455                                                    .map(|(_, enabled)| enabled)
 4456                                            })
 4457                                            .unwrap_or(true);
 4458
 4459                                        let is_delimiter = snapshot
 4460                                            .language_scope_at(Point::new(
 4461                                                point.row,
 4462                                                point.column + 1,
 4463                                            ))
 4464                                            .and_then(|scope| {
 4465                                                scope
 4466                                                    .brackets()
 4467                                                    .find(|(pair, _)| {
 4468                                                        pair.start == bracket_pair.start
 4469                                                    })
 4470                                                    .map(|(_, enabled)| !enabled)
 4471                                            })
 4472                                            .unwrap_or(false);
 4473
 4474                                        is_enabled && !is_delimiter
 4475                                    })
 4476                                    .count();
 4477                                current_line_count % 2 == 1
 4478                            } else {
 4479                                false
 4480                            };
 4481
 4482                            if autoclose
 4483                                && bracket_pair.close
 4484                                && following_text_allows_autoclose
 4485                                && preceding_text_allows_autoclose
 4486                                && !is_closing_quote
 4487                            {
 4488                                let anchor = snapshot.anchor_before(selection.end);
 4489                                new_selections.push((selection.map(|_| anchor), text.len()));
 4490                                new_autoclose_regions.push((
 4491                                    anchor,
 4492                                    text.len(),
 4493                                    selection.id,
 4494                                    bracket_pair.clone(),
 4495                                ));
 4496                                edits.push((
 4497                                    selection.range(),
 4498                                    format!("{}{}", text, bracket_pair.end).into(),
 4499                                ));
 4500                                bracket_inserted = true;
 4501                                continue;
 4502                            }
 4503                        }
 4504
 4505                        if let Some(region) = autoclose_region {
 4506                            // If the selection is followed by an auto-inserted closing bracket,
 4507                            // then don't insert that closing bracket again; just move the selection
 4508                            // past the closing bracket.
 4509                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4510                                && text.as_ref() == region.pair.end.as_str()
 4511                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4512                            if should_skip {
 4513                                let anchor = snapshot.anchor_after(selection.end);
 4514                                new_selections
 4515                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4516                                continue;
 4517                            }
 4518                        }
 4519
 4520                        let always_treat_brackets_as_autoclosed = snapshot
 4521                            .language_settings_at(selection.start, cx)
 4522                            .always_treat_brackets_as_autoclosed;
 4523                        if always_treat_brackets_as_autoclosed
 4524                            && is_bracket_pair_end
 4525                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4526                        {
 4527                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4528                            // and the inserted text is a closing bracket and the selection is followed
 4529                            // by the closing bracket then move the selection past the closing bracket.
 4530                            let anchor = snapshot.anchor_after(selection.end);
 4531                            new_selections.push((selection.map(|_| anchor), text.len()));
 4532                            continue;
 4533                        }
 4534                    }
 4535                    // If an opening bracket is 1 character long and is typed while
 4536                    // text is selected, then surround that text with the bracket pair.
 4537                    else if auto_surround
 4538                        && bracket_pair.surround
 4539                        && is_bracket_pair_start
 4540                        && bracket_pair.start.chars().count() == 1
 4541                    {
 4542                        edits.push((selection.start..selection.start, text.clone()));
 4543                        edits.push((
 4544                            selection.end..selection.end,
 4545                            bracket_pair.end.as_str().into(),
 4546                        ));
 4547                        bracket_inserted = true;
 4548                        new_selections.push((
 4549                            Selection {
 4550                                id: selection.id,
 4551                                start: snapshot.anchor_after(selection.start),
 4552                                end: snapshot.anchor_before(selection.end),
 4553                                reversed: selection.reversed,
 4554                                goal: selection.goal,
 4555                            },
 4556                            0,
 4557                        ));
 4558                        continue;
 4559                    }
 4560                }
 4561            }
 4562
 4563            if self.auto_replace_emoji_shortcode
 4564                && selection.is_empty()
 4565                && text.as_ref().ends_with(':')
 4566                && let Some(possible_emoji_short_code) =
 4567                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4568                && !possible_emoji_short_code.is_empty()
 4569                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4570            {
 4571                let emoji_shortcode_start = Point::new(
 4572                    selection.start.row,
 4573                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4574                );
 4575
 4576                // Remove shortcode from buffer
 4577                edits.push((
 4578                    emoji_shortcode_start..selection.start,
 4579                    "".to_string().into(),
 4580                ));
 4581                new_selections.push((
 4582                    Selection {
 4583                        id: selection.id,
 4584                        start: snapshot.anchor_after(emoji_shortcode_start),
 4585                        end: snapshot.anchor_before(selection.start),
 4586                        reversed: selection.reversed,
 4587                        goal: selection.goal,
 4588                    },
 4589                    0,
 4590                ));
 4591
 4592                // Insert emoji
 4593                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4594                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4595                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4596
 4597                continue;
 4598            }
 4599
 4600            let next_is_adjacent = regions
 4601                .peek()
 4602                .is_some_and(|(next, _)| selection.end == next.start);
 4603
 4604            // If not handling any auto-close operation, then just replace the selected
 4605            // text with the given input and move the selection to the end of the
 4606            // newly inserted text.
 4607            let anchor = if in_adjacent_group || next_is_adjacent {
 4608                // After edits the right bias would shift those anchor to the next visible fragment
 4609                // but we want to resolve to the previous one
 4610                snapshot.anchor_before(selection.end)
 4611            } else {
 4612                snapshot.anchor_after(selection.end)
 4613            };
 4614
 4615            if !self.linked_edit_ranges.is_empty() {
 4616                let start_anchor = snapshot.anchor_before(selection.start);
 4617
 4618                let is_word_char = text.chars().next().is_none_or(|char| {
 4619                    let classifier = snapshot
 4620                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4621                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4622                    classifier.is_word(char)
 4623                });
 4624
 4625                if is_word_char {
 4626                    if let Some(ranges) = self
 4627                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4628                    {
 4629                        for (buffer, edits) in ranges {
 4630                            linked_edits
 4631                                .entry(buffer.clone())
 4632                                .or_default()
 4633                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4634                        }
 4635                    }
 4636                } else {
 4637                    clear_linked_edit_ranges = true;
 4638                }
 4639            }
 4640
 4641            new_selections.push((selection.map(|_| anchor), 0));
 4642            edits.push((selection.start..selection.end, text.clone()));
 4643
 4644            has_adjacent_edits |= next_is_adjacent;
 4645            in_adjacent_group = next_is_adjacent;
 4646        }
 4647
 4648        if all_selections_read_only {
 4649            return;
 4650        }
 4651
 4652        drop(regions);
 4653        drop(snapshot);
 4654
 4655        self.transact(window, cx, |this, window, cx| {
 4656            if clear_linked_edit_ranges {
 4657                this.linked_edit_ranges.clear();
 4658            }
 4659            let initial_buffer_versions =
 4660                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4661
 4662            this.buffer.update(cx, |buffer, cx| {
 4663                if has_adjacent_edits {
 4664                    buffer.edit_non_coalesce(edits, this.autoindent_mode.clone(), cx);
 4665                } else {
 4666                    buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4667                }
 4668            });
 4669            for (buffer, edits) in linked_edits {
 4670                buffer.update(cx, |buffer, cx| {
 4671                    let snapshot = buffer.snapshot();
 4672                    let edits = edits
 4673                        .into_iter()
 4674                        .map(|(range, text)| {
 4675                            use text::ToPoint as TP;
 4676                            let end_point = TP::to_point(&range.end, &snapshot);
 4677                            let start_point = TP::to_point(&range.start, &snapshot);
 4678                            (start_point..end_point, text)
 4679                        })
 4680                        .sorted_by_key(|(range, _)| range.start);
 4681                    buffer.edit(edits, None, cx);
 4682                })
 4683            }
 4684            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4685            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4686            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4687            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4688                new_anchor_selections,
 4689                &map,
 4690            )
 4691            .zip(new_selection_deltas)
 4692            .map(|(selection, delta)| Selection {
 4693                id: selection.id,
 4694                start: selection.start + delta,
 4695                end: selection.end + delta,
 4696                reversed: selection.reversed,
 4697                goal: SelectionGoal::None,
 4698            })
 4699            .collect::<Vec<_>>();
 4700
 4701            let mut i = 0;
 4702            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4703                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4704                let start = map.buffer_snapshot().anchor_before(position);
 4705                let end = map.buffer_snapshot().anchor_after(position);
 4706                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4707                    match existing_state
 4708                        .range
 4709                        .start
 4710                        .cmp(&start, map.buffer_snapshot())
 4711                    {
 4712                        Ordering::Less => i += 1,
 4713                        Ordering::Greater => break,
 4714                        Ordering::Equal => {
 4715                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4716                                Ordering::Less => i += 1,
 4717                                Ordering::Equal => break,
 4718                                Ordering::Greater => break,
 4719                            }
 4720                        }
 4721                    }
 4722                }
 4723                this.autoclose_regions.insert(
 4724                    i,
 4725                    AutocloseRegion {
 4726                        selection_id,
 4727                        range: start..end,
 4728                        pair,
 4729                    },
 4730                );
 4731            }
 4732
 4733            let had_active_edit_prediction = this.has_active_edit_prediction();
 4734            this.change_selections(
 4735                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4736                window,
 4737                cx,
 4738                |s| s.select(new_selections),
 4739            );
 4740
 4741            if !bracket_inserted
 4742                && let Some(on_type_format_task) =
 4743                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4744            {
 4745                on_type_format_task.detach_and_log_err(cx);
 4746            }
 4747
 4748            let editor_settings = EditorSettings::get_global(cx);
 4749            if bracket_inserted
 4750                && (editor_settings.auto_signature_help
 4751                    || editor_settings.show_signature_help_after_edits)
 4752            {
 4753                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4754            }
 4755
 4756            let trigger_in_words =
 4757                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4758            if this.hard_wrap.is_some() {
 4759                let latest: Range<Point> = this.selections.newest(&map).range();
 4760                if latest.is_empty()
 4761                    && this
 4762                        .buffer()
 4763                        .read(cx)
 4764                        .snapshot(cx)
 4765                        .line_len(MultiBufferRow(latest.start.row))
 4766                        == latest.start.column
 4767                {
 4768                    this.rewrap_impl(
 4769                        RewrapOptions {
 4770                            override_language_settings: true,
 4771                            preserve_existing_whitespace: true,
 4772                        },
 4773                        cx,
 4774                    )
 4775                }
 4776            }
 4777            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4778            refresh_linked_ranges(this, window, cx);
 4779            this.refresh_edit_prediction(true, false, window, cx);
 4780            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4781        });
 4782    }
 4783
 4784    fn find_possible_emoji_shortcode_at_position(
 4785        snapshot: &MultiBufferSnapshot,
 4786        position: Point,
 4787    ) -> Option<String> {
 4788        let mut chars = Vec::new();
 4789        let mut found_colon = false;
 4790        for char in snapshot.reversed_chars_at(position).take(100) {
 4791            // Found a possible emoji shortcode in the middle of the buffer
 4792            if found_colon {
 4793                if char.is_whitespace() {
 4794                    chars.reverse();
 4795                    return Some(chars.iter().collect());
 4796                }
 4797                // If the previous character is not a whitespace, we are in the middle of a word
 4798                // and we only want to complete the shortcode if the word is made up of other emojis
 4799                let mut containing_word = String::new();
 4800                for ch in snapshot
 4801                    .reversed_chars_at(position)
 4802                    .skip(chars.len() + 1)
 4803                    .take(100)
 4804                {
 4805                    if ch.is_whitespace() {
 4806                        break;
 4807                    }
 4808                    containing_word.push(ch);
 4809                }
 4810                let containing_word = containing_word.chars().rev().collect::<String>();
 4811                if util::word_consists_of_emojis(containing_word.as_str()) {
 4812                    chars.reverse();
 4813                    return Some(chars.iter().collect());
 4814                }
 4815            }
 4816
 4817            if char.is_whitespace() || !char.is_ascii() {
 4818                return None;
 4819            }
 4820            if char == ':' {
 4821                found_colon = true;
 4822            } else {
 4823                chars.push(char);
 4824            }
 4825        }
 4826        // Found a possible emoji shortcode at the beginning of the buffer
 4827        chars.reverse();
 4828        Some(chars.iter().collect())
 4829    }
 4830
 4831    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4832        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4833        self.transact(window, cx, |this, window, cx| {
 4834            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4835                let selections = this
 4836                    .selections
 4837                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4838                let multi_buffer = this.buffer.read(cx);
 4839                let buffer = multi_buffer.snapshot(cx);
 4840                selections
 4841                    .iter()
 4842                    .map(|selection| {
 4843                        let start_point = selection.start.to_point(&buffer);
 4844                        let mut existing_indent =
 4845                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4846                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4847                        let start = selection.start;
 4848                        let end = selection.end;
 4849                        let selection_is_empty = start == end;
 4850                        let language_scope = buffer.language_scope_at(start);
 4851                        let (delimiter, newline_config) = if let Some(language) = &language_scope {
 4852                            let needs_extra_newline = NewlineConfig::insert_extra_newline_brackets(
 4853                                &buffer,
 4854                                start..end,
 4855                                language,
 4856                            )
 4857                                || NewlineConfig::insert_extra_newline_tree_sitter(
 4858                                    &buffer,
 4859                                    start..end,
 4860                                );
 4861
 4862                            let mut newline_config = NewlineConfig::Newline {
 4863                                additional_indent: IndentSize::spaces(0),
 4864                                extra_line_additional_indent: if needs_extra_newline {
 4865                                    Some(IndentSize::spaces(0))
 4866                                } else {
 4867                                    None
 4868                                },
 4869                                prevent_auto_indent: false,
 4870                            };
 4871
 4872                            let comment_delimiter = maybe!({
 4873                                if !selection_is_empty {
 4874                                    return None;
 4875                                }
 4876
 4877                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4878                                    return None;
 4879                                }
 4880
 4881                                return comment_delimiter_for_newline(
 4882                                    &start_point,
 4883                                    &buffer,
 4884                                    language,
 4885                                );
 4886                            });
 4887
 4888                            let doc_delimiter = maybe!({
 4889                                if !selection_is_empty {
 4890                                    return None;
 4891                                }
 4892
 4893                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4894                                    return None;
 4895                                }
 4896
 4897                                return documentation_delimiter_for_newline(
 4898                                    &start_point,
 4899                                    &buffer,
 4900                                    language,
 4901                                    &mut newline_config,
 4902                                );
 4903                            });
 4904
 4905                            let list_delimiter = maybe!({
 4906                                if !selection_is_empty {
 4907                                    return None;
 4908                                }
 4909
 4910                                if !multi_buffer.language_settings(cx).extend_list_on_newline {
 4911                                    return None;
 4912                                }
 4913
 4914                                return list_delimiter_for_newline(
 4915                                    &start_point,
 4916                                    &buffer,
 4917                                    language,
 4918                                    &mut newline_config,
 4919                                );
 4920                            });
 4921
 4922                            (
 4923                                comment_delimiter.or(doc_delimiter).or(list_delimiter),
 4924                                newline_config,
 4925                            )
 4926                        } else {
 4927                            (
 4928                                None,
 4929                                NewlineConfig::Newline {
 4930                                    additional_indent: IndentSize::spaces(0),
 4931                                    extra_line_additional_indent: None,
 4932                                    prevent_auto_indent: false,
 4933                                },
 4934                            )
 4935                        };
 4936
 4937                        let (edit_start, new_text, prevent_auto_indent) = match &newline_config {
 4938                            NewlineConfig::ClearCurrentLine => {
 4939                                let row_start =
 4940                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 4941                                (row_start, String::new(), false)
 4942                            }
 4943                            NewlineConfig::UnindentCurrentLine { continuation } => {
 4944                                let row_start =
 4945                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 4946                                let tab_size = buffer.language_settings_at(start, cx).tab_size;
 4947                                let tab_size_indent = IndentSize::spaces(tab_size.get());
 4948                                let reduced_indent =
 4949                                    existing_indent.with_delta(Ordering::Less, tab_size_indent);
 4950                                let mut new_text = String::new();
 4951                                new_text.extend(reduced_indent.chars());
 4952                                new_text.push_str(continuation);
 4953                                (row_start, new_text, true)
 4954                            }
 4955                            NewlineConfig::Newline {
 4956                                additional_indent,
 4957                                extra_line_additional_indent,
 4958                                prevent_auto_indent,
 4959                            } => {
 4960                                let capacity_for_delimiter =
 4961                                    delimiter.as_deref().map(str::len).unwrap_or_default();
 4962                                let extra_line_len = extra_line_additional_indent
 4963                                    .map(|i| 1 + existing_indent.len as usize + i.len as usize)
 4964                                    .unwrap_or(0);
 4965                                let mut new_text = String::with_capacity(
 4966                                    1 + capacity_for_delimiter
 4967                                        + existing_indent.len as usize
 4968                                        + additional_indent.len as usize
 4969                                        + extra_line_len,
 4970                                );
 4971                                new_text.push('\n');
 4972                                new_text.extend(existing_indent.chars());
 4973                                new_text.extend(additional_indent.chars());
 4974                                if let Some(delimiter) = &delimiter {
 4975                                    new_text.push_str(delimiter);
 4976                                }
 4977                                if let Some(extra_indent) = extra_line_additional_indent {
 4978                                    new_text.push('\n');
 4979                                    new_text.extend(existing_indent.chars());
 4980                                    new_text.extend(extra_indent.chars());
 4981                                }
 4982                                (start, new_text, *prevent_auto_indent)
 4983                            }
 4984                        };
 4985
 4986                        let anchor = buffer.anchor_after(end);
 4987                        let new_selection = selection.map(|_| anchor);
 4988                        (
 4989                            ((edit_start..end, new_text), prevent_auto_indent),
 4990                            (newline_config.has_extra_line(), new_selection),
 4991                        )
 4992                    })
 4993                    .unzip()
 4994            };
 4995
 4996            let mut auto_indent_edits = Vec::new();
 4997            let mut edits = Vec::new();
 4998            for (edit, prevent_auto_indent) in edits_with_flags {
 4999                if prevent_auto_indent {
 5000                    edits.push(edit);
 5001                } else {
 5002                    auto_indent_edits.push(edit);
 5003                }
 5004            }
 5005            if !edits.is_empty() {
 5006                this.edit(edits, cx);
 5007            }
 5008            if !auto_indent_edits.is_empty() {
 5009                this.edit_with_autoindent(auto_indent_edits, cx);
 5010            }
 5011
 5012            let buffer = this.buffer.read(cx).snapshot(cx);
 5013            let new_selections = selection_info
 5014                .into_iter()
 5015                .map(|(extra_newline_inserted, new_selection)| {
 5016                    let mut cursor = new_selection.end.to_point(&buffer);
 5017                    if extra_newline_inserted {
 5018                        cursor.row -= 1;
 5019                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5020                    }
 5021                    new_selection.map(|_| cursor)
 5022                })
 5023                .collect();
 5024
 5025            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5026            this.refresh_edit_prediction(true, false, window, cx);
 5027            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5028                task.detach_and_log_err(cx);
 5029            }
 5030        });
 5031    }
 5032
 5033    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5034        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5035
 5036        let buffer = self.buffer.read(cx);
 5037        let snapshot = buffer.snapshot(cx);
 5038
 5039        let mut edits = Vec::new();
 5040        let mut rows = Vec::new();
 5041
 5042        for (rows_inserted, selection) in self
 5043            .selections
 5044            .all_adjusted(&self.display_snapshot(cx))
 5045            .into_iter()
 5046            .enumerate()
 5047        {
 5048            let cursor = selection.head();
 5049            let row = cursor.row;
 5050
 5051            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5052
 5053            let newline = "\n".to_string();
 5054            edits.push((start_of_line..start_of_line, newline));
 5055
 5056            rows.push(row + rows_inserted as u32);
 5057        }
 5058
 5059        self.transact(window, cx, |editor, window, cx| {
 5060            editor.edit(edits, cx);
 5061
 5062            editor.change_selections(Default::default(), window, cx, |s| {
 5063                let mut index = 0;
 5064                s.move_cursors_with(|map, _, _| {
 5065                    let row = rows[index];
 5066                    index += 1;
 5067
 5068                    let point = Point::new(row, 0);
 5069                    let boundary = map.next_line_boundary(point).1;
 5070                    let clipped = map.clip_point(boundary, Bias::Left);
 5071
 5072                    (clipped, SelectionGoal::None)
 5073                });
 5074            });
 5075
 5076            let mut indent_edits = Vec::new();
 5077            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5078            for row in rows {
 5079                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5080                for (row, indent) in indents {
 5081                    if indent.len == 0 {
 5082                        continue;
 5083                    }
 5084
 5085                    let text = match indent.kind {
 5086                        IndentKind::Space => " ".repeat(indent.len as usize),
 5087                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5088                    };
 5089                    let point = Point::new(row.0, 0);
 5090                    indent_edits.push((point..point, text));
 5091                }
 5092            }
 5093            editor.edit(indent_edits, cx);
 5094            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5095                format.detach_and_log_err(cx);
 5096            }
 5097        });
 5098    }
 5099
 5100    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5101        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5102
 5103        let buffer = self.buffer.read(cx);
 5104        let snapshot = buffer.snapshot(cx);
 5105
 5106        let mut edits = Vec::new();
 5107        let mut rows = Vec::new();
 5108        let mut rows_inserted = 0;
 5109
 5110        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5111            let cursor = selection.head();
 5112            let row = cursor.row;
 5113
 5114            let point = Point::new(row + 1, 0);
 5115            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5116
 5117            let newline = "\n".to_string();
 5118            edits.push((start_of_line..start_of_line, newline));
 5119
 5120            rows_inserted += 1;
 5121            rows.push(row + rows_inserted);
 5122        }
 5123
 5124        self.transact(window, cx, |editor, window, cx| {
 5125            editor.edit(edits, cx);
 5126
 5127            editor.change_selections(Default::default(), window, cx, |s| {
 5128                let mut index = 0;
 5129                s.move_cursors_with(|map, _, _| {
 5130                    let row = rows[index];
 5131                    index += 1;
 5132
 5133                    let point = Point::new(row, 0);
 5134                    let boundary = map.next_line_boundary(point).1;
 5135                    let clipped = map.clip_point(boundary, Bias::Left);
 5136
 5137                    (clipped, SelectionGoal::None)
 5138                });
 5139            });
 5140
 5141            let mut indent_edits = Vec::new();
 5142            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5143            for row in rows {
 5144                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5145                for (row, indent) in indents {
 5146                    if indent.len == 0 {
 5147                        continue;
 5148                    }
 5149
 5150                    let text = match indent.kind {
 5151                        IndentKind::Space => " ".repeat(indent.len as usize),
 5152                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5153                    };
 5154                    let point = Point::new(row.0, 0);
 5155                    indent_edits.push((point..point, text));
 5156                }
 5157            }
 5158            editor.edit(indent_edits, cx);
 5159            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5160                format.detach_and_log_err(cx);
 5161            }
 5162        });
 5163    }
 5164
 5165    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5166        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5167            original_indent_columns: Vec::new(),
 5168        });
 5169        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5170    }
 5171
 5172    fn insert_with_autoindent_mode(
 5173        &mut self,
 5174        text: &str,
 5175        autoindent_mode: Option<AutoindentMode>,
 5176        window: &mut Window,
 5177        cx: &mut Context<Self>,
 5178    ) {
 5179        if self.read_only(cx) {
 5180            return;
 5181        }
 5182
 5183        let text: Arc<str> = text.into();
 5184        self.transact(window, cx, |this, window, cx| {
 5185            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5186            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5187                let anchors = {
 5188                    let snapshot = buffer.read(cx);
 5189                    old_selections
 5190                        .iter()
 5191                        .map(|s| {
 5192                            let anchor = snapshot.anchor_after(s.head());
 5193                            s.map(|_| anchor)
 5194                        })
 5195                        .collect::<Vec<_>>()
 5196                };
 5197                buffer.edit(
 5198                    old_selections
 5199                        .iter()
 5200                        .map(|s| (s.start..s.end, text.clone())),
 5201                    autoindent_mode,
 5202                    cx,
 5203                );
 5204                anchors
 5205            });
 5206
 5207            this.change_selections(Default::default(), window, cx, |s| {
 5208                s.select_anchors(selection_anchors);
 5209            });
 5210
 5211            cx.notify();
 5212        });
 5213    }
 5214
 5215    fn trigger_completion_on_input(
 5216        &mut self,
 5217        text: &str,
 5218        trigger_in_words: bool,
 5219        window: &mut Window,
 5220        cx: &mut Context<Self>,
 5221    ) {
 5222        let completions_source = self
 5223            .context_menu
 5224            .borrow()
 5225            .as_ref()
 5226            .and_then(|menu| match menu {
 5227                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5228                CodeContextMenu::CodeActions(_) => None,
 5229            });
 5230
 5231        match completions_source {
 5232            Some(CompletionsMenuSource::Words { .. }) => {
 5233                self.open_or_update_completions_menu(
 5234                    Some(CompletionsMenuSource::Words {
 5235                        ignore_threshold: false,
 5236                    }),
 5237                    None,
 5238                    trigger_in_words,
 5239                    window,
 5240                    cx,
 5241                );
 5242            }
 5243            _ => self.open_or_update_completions_menu(
 5244                None,
 5245                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5246                true,
 5247                window,
 5248                cx,
 5249            ),
 5250        }
 5251    }
 5252
 5253    /// If any empty selections is touching the start of its innermost containing autoclose
 5254    /// region, expand it to select the brackets.
 5255    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5256        let selections = self
 5257            .selections
 5258            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5259        let buffer = self.buffer.read(cx).read(cx);
 5260        let new_selections = self
 5261            .selections_with_autoclose_regions(selections, &buffer)
 5262            .map(|(mut selection, region)| {
 5263                if !selection.is_empty() {
 5264                    return selection;
 5265                }
 5266
 5267                if let Some(region) = region {
 5268                    let mut range = region.range.to_offset(&buffer);
 5269                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5270                        range.start -= region.pair.start.len();
 5271                        if buffer.contains_str_at(range.start, &region.pair.start)
 5272                            && buffer.contains_str_at(range.end, &region.pair.end)
 5273                        {
 5274                            range.end += region.pair.end.len();
 5275                            selection.start = range.start;
 5276                            selection.end = range.end;
 5277
 5278                            return selection;
 5279                        }
 5280                    }
 5281                }
 5282
 5283                let always_treat_brackets_as_autoclosed = buffer
 5284                    .language_settings_at(selection.start, cx)
 5285                    .always_treat_brackets_as_autoclosed;
 5286
 5287                if !always_treat_brackets_as_autoclosed {
 5288                    return selection;
 5289                }
 5290
 5291                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5292                    for (pair, enabled) in scope.brackets() {
 5293                        if !enabled || !pair.close {
 5294                            continue;
 5295                        }
 5296
 5297                        if buffer.contains_str_at(selection.start, &pair.end) {
 5298                            let pair_start_len = pair.start.len();
 5299                            if buffer.contains_str_at(
 5300                                selection.start.saturating_sub_usize(pair_start_len),
 5301                                &pair.start,
 5302                            ) {
 5303                                selection.start -= pair_start_len;
 5304                                selection.end += pair.end.len();
 5305
 5306                                return selection;
 5307                            }
 5308                        }
 5309                    }
 5310                }
 5311
 5312                selection
 5313            })
 5314            .collect();
 5315
 5316        drop(buffer);
 5317        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5318            selections.select(new_selections)
 5319        });
 5320    }
 5321
 5322    /// Iterate the given selections, and for each one, find the smallest surrounding
 5323    /// autoclose region. This uses the ordering of the selections and the autoclose
 5324    /// regions to avoid repeated comparisons.
 5325    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5326        &'a self,
 5327        selections: impl IntoIterator<Item = Selection<D>>,
 5328        buffer: &'a MultiBufferSnapshot,
 5329    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5330        let mut i = 0;
 5331        let mut regions = self.autoclose_regions.as_slice();
 5332        selections.into_iter().map(move |selection| {
 5333            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5334
 5335            let mut enclosing = None;
 5336            while let Some(pair_state) = regions.get(i) {
 5337                if pair_state.range.end.to_offset(buffer) < range.start {
 5338                    regions = &regions[i + 1..];
 5339                    i = 0;
 5340                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5341                    break;
 5342                } else {
 5343                    if pair_state.selection_id == selection.id {
 5344                        enclosing = Some(pair_state);
 5345                    }
 5346                    i += 1;
 5347                }
 5348            }
 5349
 5350            (selection, enclosing)
 5351        })
 5352    }
 5353
 5354    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5355    fn invalidate_autoclose_regions(
 5356        &mut self,
 5357        mut selections: &[Selection<Anchor>],
 5358        buffer: &MultiBufferSnapshot,
 5359    ) {
 5360        self.autoclose_regions.retain(|state| {
 5361            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5362                return false;
 5363            }
 5364
 5365            let mut i = 0;
 5366            while let Some(selection) = selections.get(i) {
 5367                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5368                    selections = &selections[1..];
 5369                    continue;
 5370                }
 5371                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5372                    break;
 5373                }
 5374                if selection.id == state.selection_id {
 5375                    return true;
 5376                } else {
 5377                    i += 1;
 5378                }
 5379            }
 5380            false
 5381        });
 5382    }
 5383
 5384    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5385        let offset = position.to_offset(buffer);
 5386        let (word_range, kind) =
 5387            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5388        if offset > word_range.start && kind == Some(CharKind::Word) {
 5389            Some(
 5390                buffer
 5391                    .text_for_range(word_range.start..offset)
 5392                    .collect::<String>(),
 5393            )
 5394        } else {
 5395            None
 5396        }
 5397    }
 5398
 5399    pub fn visible_excerpts(
 5400        &self,
 5401        lsp_related_only: bool,
 5402        cx: &mut Context<Editor>,
 5403    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5404        let project = self.project().cloned();
 5405        let multi_buffer = self.buffer().read(cx);
 5406        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5407        let multi_buffer_visible_start = self
 5408            .scroll_manager
 5409            .anchor()
 5410            .anchor
 5411            .to_point(&multi_buffer_snapshot);
 5412        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5413            multi_buffer_visible_start
 5414                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5415            Bias::Left,
 5416        );
 5417        multi_buffer_snapshot
 5418            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5419            .into_iter()
 5420            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5421            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5422                if !lsp_related_only {
 5423                    return Some((
 5424                        excerpt_id,
 5425                        (
 5426                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5427                            buffer.version().clone(),
 5428                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5429                        ),
 5430                    ));
 5431                }
 5432
 5433                let project = project.as_ref()?.read(cx);
 5434                let buffer_file = project::File::from_dyn(buffer.file())?;
 5435                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5436                let worktree_entry = buffer_worktree
 5437                    .read(cx)
 5438                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5439                if worktree_entry.is_ignored {
 5440                    None
 5441                } else {
 5442                    Some((
 5443                        excerpt_id,
 5444                        (
 5445                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5446                            buffer.version().clone(),
 5447                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5448                        ),
 5449                    ))
 5450                }
 5451            })
 5452            .collect()
 5453    }
 5454
 5455    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5456        TextLayoutDetails {
 5457            text_system: window.text_system().clone(),
 5458            editor_style: self.style.clone().unwrap(),
 5459            rem_size: window.rem_size(),
 5460            scroll_anchor: self.scroll_manager.anchor(),
 5461            visible_rows: self.visible_line_count(),
 5462            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5463        }
 5464    }
 5465
 5466    fn trigger_on_type_formatting(
 5467        &self,
 5468        input: String,
 5469        window: &mut Window,
 5470        cx: &mut Context<Self>,
 5471    ) -> Option<Task<Result<()>>> {
 5472        if input.chars().count() != 1 {
 5473            return None;
 5474        }
 5475
 5476        let project = self.project()?;
 5477        let position = self.selections.newest_anchor().head();
 5478        let (buffer, buffer_position) = self
 5479            .buffer
 5480            .read(cx)
 5481            .text_anchor_for_position(position, cx)?;
 5482
 5483        let settings = language_settings::language_settings(
 5484            buffer
 5485                .read(cx)
 5486                .language_at(buffer_position)
 5487                .map(|l| l.name()),
 5488            buffer.read(cx).file(),
 5489            cx,
 5490        );
 5491        if !settings.use_on_type_format {
 5492            return None;
 5493        }
 5494
 5495        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5496        // hence we do LSP request & edit on host side only — add formats to host's history.
 5497        let push_to_lsp_host_history = true;
 5498        // If this is not the host, append its history with new edits.
 5499        let push_to_client_history = project.read(cx).is_via_collab();
 5500
 5501        let on_type_formatting = project.update(cx, |project, cx| {
 5502            project.on_type_format(
 5503                buffer.clone(),
 5504                buffer_position,
 5505                input,
 5506                push_to_lsp_host_history,
 5507                cx,
 5508            )
 5509        });
 5510        Some(cx.spawn_in(window, async move |editor, cx| {
 5511            if let Some(transaction) = on_type_formatting.await? {
 5512                if push_to_client_history {
 5513                    buffer
 5514                        .update(cx, |buffer, _| {
 5515                            buffer.push_transaction(transaction, Instant::now());
 5516                            buffer.finalize_last_transaction();
 5517                        })
 5518                        .ok();
 5519                }
 5520                editor.update(cx, |editor, cx| {
 5521                    editor.refresh_document_highlights(cx);
 5522                })?;
 5523            }
 5524            Ok(())
 5525        }))
 5526    }
 5527
 5528    pub fn show_word_completions(
 5529        &mut self,
 5530        _: &ShowWordCompletions,
 5531        window: &mut Window,
 5532        cx: &mut Context<Self>,
 5533    ) {
 5534        self.open_or_update_completions_menu(
 5535            Some(CompletionsMenuSource::Words {
 5536                ignore_threshold: true,
 5537            }),
 5538            None,
 5539            false,
 5540            window,
 5541            cx,
 5542        );
 5543    }
 5544
 5545    pub fn show_completions(
 5546        &mut self,
 5547        _: &ShowCompletions,
 5548        window: &mut Window,
 5549        cx: &mut Context<Self>,
 5550    ) {
 5551        self.open_or_update_completions_menu(None, None, false, window, cx);
 5552    }
 5553
 5554    fn open_or_update_completions_menu(
 5555        &mut self,
 5556        requested_source: Option<CompletionsMenuSource>,
 5557        trigger: Option<String>,
 5558        trigger_in_words: bool,
 5559        window: &mut Window,
 5560        cx: &mut Context<Self>,
 5561    ) {
 5562        if self.pending_rename.is_some() {
 5563            return;
 5564        }
 5565
 5566        let completions_source = self
 5567            .context_menu
 5568            .borrow()
 5569            .as_ref()
 5570            .and_then(|menu| match menu {
 5571                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5572                CodeContextMenu::CodeActions(_) => None,
 5573            });
 5574
 5575        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5576
 5577        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5578        // inserted and selected. To handle that case, the start of the selection is used so that
 5579        // the menu starts with all choices.
 5580        let position = self
 5581            .selections
 5582            .newest_anchor()
 5583            .start
 5584            .bias_right(&multibuffer_snapshot);
 5585        if position.diff_base_anchor.is_some() {
 5586            return;
 5587        }
 5588        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5589        let Some(buffer) = buffer_position
 5590            .text_anchor
 5591            .buffer_id
 5592            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5593        else {
 5594            return;
 5595        };
 5596        let buffer_snapshot = buffer.read(cx).snapshot();
 5597
 5598        let menu_is_open = matches!(
 5599            self.context_menu.borrow().as_ref(),
 5600            Some(CodeContextMenu::Completions(_))
 5601        );
 5602
 5603        let language = buffer_snapshot
 5604            .language_at(buffer_position.text_anchor)
 5605            .map(|language| language.name());
 5606
 5607        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5608        let completion_settings = language_settings.completions.clone();
 5609
 5610        let show_completions_on_input = self
 5611            .show_completions_on_input_override
 5612            .unwrap_or(language_settings.show_completions_on_input);
 5613        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5614            return;
 5615        }
 5616
 5617        let query: Option<Arc<String>> =
 5618            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5619                .map(|query| query.into());
 5620
 5621        drop(multibuffer_snapshot);
 5622
 5623        // Hide the current completions menu when query is empty. Without this, cached
 5624        // completions from before the trigger char may be reused (#32774).
 5625        if query.is_none() && menu_is_open {
 5626            self.hide_context_menu(window, cx);
 5627        }
 5628
 5629        let mut ignore_word_threshold = false;
 5630        let provider = match requested_source {
 5631            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5632            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5633                ignore_word_threshold = ignore_threshold;
 5634                None
 5635            }
 5636            Some(CompletionsMenuSource::SnippetChoices)
 5637            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5638                log::error!("bug: SnippetChoices requested_source is not handled");
 5639                None
 5640            }
 5641        };
 5642
 5643        let sort_completions = provider
 5644            .as_ref()
 5645            .is_some_and(|provider| provider.sort_completions());
 5646
 5647        let filter_completions = provider
 5648            .as_ref()
 5649            .is_none_or(|provider| provider.filter_completions());
 5650
 5651        let was_snippets_only = matches!(
 5652            completions_source,
 5653            Some(CompletionsMenuSource::SnippetsOnly)
 5654        );
 5655
 5656        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5657            if filter_completions {
 5658                menu.filter(
 5659                    query.clone().unwrap_or_default(),
 5660                    buffer_position.text_anchor,
 5661                    &buffer,
 5662                    provider.clone(),
 5663                    window,
 5664                    cx,
 5665                );
 5666            }
 5667            // When `is_incomplete` is false, no need to re-query completions when the current query
 5668            // is a suffix of the initial query.
 5669            let was_complete = !menu.is_incomplete;
 5670            if was_complete && !was_snippets_only {
 5671                // If the new query is a suffix of the old query (typing more characters) and
 5672                // the previous result was complete, the existing completions can be filtered.
 5673                //
 5674                // Note that snippet completions are always complete.
 5675                let query_matches = match (&menu.initial_query, &query) {
 5676                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5677                    (None, _) => true,
 5678                    _ => false,
 5679                };
 5680                if query_matches {
 5681                    let position_matches = if menu.initial_position == position {
 5682                        true
 5683                    } else {
 5684                        let snapshot = self.buffer.read(cx).read(cx);
 5685                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5686                    };
 5687                    if position_matches {
 5688                        return;
 5689                    }
 5690                }
 5691            }
 5692        };
 5693
 5694        let Anchor {
 5695            excerpt_id: buffer_excerpt_id,
 5696            text_anchor: buffer_position,
 5697            ..
 5698        } = buffer_position;
 5699
 5700        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5701            buffer_snapshot.surrounding_word(buffer_position, None)
 5702        {
 5703            let word_to_exclude = buffer_snapshot
 5704                .text_for_range(word_range.clone())
 5705                .collect::<String>();
 5706            (
 5707                buffer_snapshot.anchor_before(word_range.start)
 5708                    ..buffer_snapshot.anchor_after(buffer_position),
 5709                Some(word_to_exclude),
 5710            )
 5711        } else {
 5712            (buffer_position..buffer_position, None)
 5713        };
 5714
 5715        let show_completion_documentation = buffer_snapshot
 5716            .settings_at(buffer_position, cx)
 5717            .show_completion_documentation;
 5718
 5719        // The document can be large, so stay in reasonable bounds when searching for words,
 5720        // otherwise completion pop-up might be slow to appear.
 5721        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5722        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5723        let min_word_search = buffer_snapshot.clip_point(
 5724            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5725            Bias::Left,
 5726        );
 5727        let max_word_search = buffer_snapshot.clip_point(
 5728            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5729            Bias::Right,
 5730        );
 5731        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5732            ..buffer_snapshot.point_to_offset(max_word_search);
 5733
 5734        let skip_digits = query
 5735            .as_ref()
 5736            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5737
 5738        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5739            trigger.as_ref().is_none_or(|trigger| {
 5740                provider.is_completion_trigger(
 5741                    &buffer,
 5742                    position.text_anchor,
 5743                    trigger,
 5744                    trigger_in_words,
 5745                    cx,
 5746                )
 5747            })
 5748        });
 5749
 5750        let provider_responses = if let Some(provider) = &provider
 5751            && load_provider_completions
 5752        {
 5753            let trigger_character =
 5754                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5755            let completion_context = CompletionContext {
 5756                trigger_kind: match &trigger_character {
 5757                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5758                    None => CompletionTriggerKind::INVOKED,
 5759                },
 5760                trigger_character,
 5761            };
 5762
 5763            provider.completions(
 5764                buffer_excerpt_id,
 5765                &buffer,
 5766                buffer_position,
 5767                completion_context,
 5768                window,
 5769                cx,
 5770            )
 5771        } else {
 5772            Task::ready(Ok(Vec::new()))
 5773        };
 5774
 5775        let load_word_completions = if !self.word_completions_enabled {
 5776            false
 5777        } else if requested_source
 5778            == Some(CompletionsMenuSource::Words {
 5779                ignore_threshold: true,
 5780            })
 5781        {
 5782            true
 5783        } else {
 5784            load_provider_completions
 5785                && completion_settings.words != WordsCompletionMode::Disabled
 5786                && (ignore_word_threshold || {
 5787                    let words_min_length = completion_settings.words_min_length;
 5788                    // check whether word has at least `words_min_length` characters
 5789                    let query_chars = query.iter().flat_map(|q| q.chars());
 5790                    query_chars.take(words_min_length).count() == words_min_length
 5791                })
 5792        };
 5793
 5794        let mut words = if load_word_completions {
 5795            cx.background_spawn({
 5796                let buffer_snapshot = buffer_snapshot.clone();
 5797                async move {
 5798                    buffer_snapshot.words_in_range(WordsQuery {
 5799                        fuzzy_contents: None,
 5800                        range: word_search_range,
 5801                        skip_digits,
 5802                    })
 5803                }
 5804            })
 5805        } else {
 5806            Task::ready(BTreeMap::default())
 5807        };
 5808
 5809        let snippets = if let Some(provider) = &provider
 5810            && provider.show_snippets()
 5811            && let Some(project) = self.project()
 5812        {
 5813            let char_classifier = buffer_snapshot
 5814                .char_classifier_at(buffer_position)
 5815                .scope_context(Some(CharScopeContext::Completion));
 5816            project.update(cx, |project, cx| {
 5817                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5818            })
 5819        } else {
 5820            Task::ready(Ok(CompletionResponse {
 5821                completions: Vec::new(),
 5822                display_options: Default::default(),
 5823                is_incomplete: false,
 5824            }))
 5825        };
 5826
 5827        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5828
 5829        let id = post_inc(&mut self.next_completion_id);
 5830        let task = cx.spawn_in(window, async move |editor, cx| {
 5831            let Ok(()) = editor.update(cx, |this, _| {
 5832                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5833            }) else {
 5834                return;
 5835            };
 5836
 5837            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5838            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5839            let mut completions = Vec::new();
 5840            let mut is_incomplete = false;
 5841            let mut display_options: Option<CompletionDisplayOptions> = None;
 5842            if let Some(provider_responses) = provider_responses.await.log_err()
 5843                && !provider_responses.is_empty()
 5844            {
 5845                for response in provider_responses {
 5846                    completions.extend(response.completions);
 5847                    is_incomplete = is_incomplete || response.is_incomplete;
 5848                    match display_options.as_mut() {
 5849                        None => {
 5850                            display_options = Some(response.display_options);
 5851                        }
 5852                        Some(options) => options.merge(&response.display_options),
 5853                    }
 5854                }
 5855                if completion_settings.words == WordsCompletionMode::Fallback {
 5856                    words = Task::ready(BTreeMap::default());
 5857                }
 5858            }
 5859            let display_options = display_options.unwrap_or_default();
 5860
 5861            let mut words = words.await;
 5862            if let Some(word_to_exclude) = &word_to_exclude {
 5863                words.remove(word_to_exclude);
 5864            }
 5865            for lsp_completion in &completions {
 5866                words.remove(&lsp_completion.new_text);
 5867            }
 5868            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5869                replace_range: word_replace_range.clone(),
 5870                new_text: word.clone(),
 5871                label: CodeLabel::plain(word, None),
 5872                match_start: None,
 5873                snippet_deduplication_key: None,
 5874                icon_path: None,
 5875                documentation: None,
 5876                source: CompletionSource::BufferWord {
 5877                    word_range,
 5878                    resolved: false,
 5879                },
 5880                insert_text_mode: Some(InsertTextMode::AS_IS),
 5881                confirm: None,
 5882            }));
 5883
 5884            completions.extend(
 5885                snippets
 5886                    .await
 5887                    .into_iter()
 5888                    .flat_map(|response| response.completions),
 5889            );
 5890
 5891            let menu = if completions.is_empty() {
 5892                None
 5893            } else {
 5894                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5895                    let languages = editor
 5896                        .workspace
 5897                        .as_ref()
 5898                        .and_then(|(workspace, _)| workspace.upgrade())
 5899                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5900                    let menu = CompletionsMenu::new(
 5901                        id,
 5902                        requested_source.unwrap_or(if load_provider_completions {
 5903                            CompletionsMenuSource::Normal
 5904                        } else {
 5905                            CompletionsMenuSource::SnippetsOnly
 5906                        }),
 5907                        sort_completions,
 5908                        show_completion_documentation,
 5909                        position,
 5910                        query.clone(),
 5911                        is_incomplete,
 5912                        buffer.clone(),
 5913                        completions.into(),
 5914                        editor
 5915                            .context_menu()
 5916                            .borrow_mut()
 5917                            .as_ref()
 5918                            .map(|menu| menu.primary_scroll_handle()),
 5919                        display_options,
 5920                        snippet_sort_order,
 5921                        languages,
 5922                        language,
 5923                        cx,
 5924                    );
 5925
 5926                    let query = if filter_completions { query } else { None };
 5927                    let matches_task = menu.do_async_filtering(
 5928                        query.unwrap_or_default(),
 5929                        buffer_position,
 5930                        &buffer,
 5931                        cx,
 5932                    );
 5933                    (menu, matches_task)
 5934                }) else {
 5935                    return;
 5936                };
 5937
 5938                let matches = matches_task.await;
 5939
 5940                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5941                    // Newer menu already set, so exit.
 5942                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5943                        editor.context_menu.borrow().as_ref()
 5944                        && prev_menu.id > id
 5945                    {
 5946                        return;
 5947                    };
 5948
 5949                    // Only valid to take prev_menu because either the new menu is immediately set
 5950                    // below, or the menu is hidden.
 5951                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5952                        editor.context_menu.borrow_mut().take()
 5953                    {
 5954                        let position_matches =
 5955                            if prev_menu.initial_position == menu.initial_position {
 5956                                true
 5957                            } else {
 5958                                let snapshot = editor.buffer.read(cx).read(cx);
 5959                                prev_menu.initial_position.to_offset(&snapshot)
 5960                                    == menu.initial_position.to_offset(&snapshot)
 5961                            };
 5962                        if position_matches {
 5963                            // Preserve markdown cache before `set_filter_results` because it will
 5964                            // try to populate the documentation cache.
 5965                            menu.preserve_markdown_cache(prev_menu);
 5966                        }
 5967                    };
 5968
 5969                    menu.set_filter_results(matches, provider, window, cx);
 5970                }) else {
 5971                    return;
 5972                };
 5973
 5974                menu.visible().then_some(menu)
 5975            };
 5976
 5977            editor
 5978                .update_in(cx, |editor, window, cx| {
 5979                    if editor.focus_handle.is_focused(window)
 5980                        && let Some(menu) = menu
 5981                    {
 5982                        *editor.context_menu.borrow_mut() =
 5983                            Some(CodeContextMenu::Completions(menu));
 5984
 5985                        crate::hover_popover::hide_hover(editor, cx);
 5986                        if editor.show_edit_predictions_in_menu() {
 5987                            editor.update_visible_edit_prediction(window, cx);
 5988                        } else {
 5989                            editor.discard_edit_prediction(false, cx);
 5990                        }
 5991
 5992                        cx.notify();
 5993                        return;
 5994                    }
 5995
 5996                    if editor.completion_tasks.len() <= 1 {
 5997                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5998                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5999                        // If it was already hidden and we don't show edit predictions in the menu,
 6000                        // we should also show the edit prediction when available.
 6001                        if was_hidden && editor.show_edit_predictions_in_menu() {
 6002                            editor.update_visible_edit_prediction(window, cx);
 6003                        }
 6004                    }
 6005                })
 6006                .ok();
 6007        });
 6008
 6009        self.completion_tasks.push((id, task));
 6010    }
 6011
 6012    #[cfg(feature = "test-support")]
 6013    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6014        let menu = self.context_menu.borrow();
 6015        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6016            let completions = menu.completions.borrow();
 6017            Some(completions.to_vec())
 6018        } else {
 6019            None
 6020        }
 6021    }
 6022
 6023    pub fn with_completions_menu_matching_id<R>(
 6024        &self,
 6025        id: CompletionId,
 6026        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6027    ) -> R {
 6028        let mut context_menu = self.context_menu.borrow_mut();
 6029        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6030            return f(None);
 6031        };
 6032        if completions_menu.id != id {
 6033            return f(None);
 6034        }
 6035        f(Some(completions_menu))
 6036    }
 6037
 6038    pub fn confirm_completion(
 6039        &mut self,
 6040        action: &ConfirmCompletion,
 6041        window: &mut Window,
 6042        cx: &mut Context<Self>,
 6043    ) -> Option<Task<Result<()>>> {
 6044        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6045        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6046    }
 6047
 6048    pub fn confirm_completion_insert(
 6049        &mut self,
 6050        _: &ConfirmCompletionInsert,
 6051        window: &mut Window,
 6052        cx: &mut Context<Self>,
 6053    ) -> Option<Task<Result<()>>> {
 6054        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6055        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6056    }
 6057
 6058    pub fn confirm_completion_replace(
 6059        &mut self,
 6060        _: &ConfirmCompletionReplace,
 6061        window: &mut Window,
 6062        cx: &mut Context<Self>,
 6063    ) -> Option<Task<Result<()>>> {
 6064        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6065        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6066    }
 6067
 6068    pub fn compose_completion(
 6069        &mut self,
 6070        action: &ComposeCompletion,
 6071        window: &mut Window,
 6072        cx: &mut Context<Self>,
 6073    ) -> Option<Task<Result<()>>> {
 6074        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6075        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6076    }
 6077
 6078    fn do_completion(
 6079        &mut self,
 6080        item_ix: Option<usize>,
 6081        intent: CompletionIntent,
 6082        window: &mut Window,
 6083        cx: &mut Context<Editor>,
 6084    ) -> Option<Task<Result<()>>> {
 6085        use language::ToOffset as _;
 6086
 6087        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6088        else {
 6089            return None;
 6090        };
 6091
 6092        let candidate_id = {
 6093            let entries = completions_menu.entries.borrow();
 6094            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6095            if self.show_edit_predictions_in_menu() {
 6096                self.discard_edit_prediction(true, cx);
 6097            }
 6098            mat.candidate_id
 6099        };
 6100
 6101        let completion = completions_menu
 6102            .completions
 6103            .borrow()
 6104            .get(candidate_id)?
 6105            .clone();
 6106        cx.stop_propagation();
 6107
 6108        let buffer_handle = completions_menu.buffer.clone();
 6109
 6110        let CompletionEdit {
 6111            new_text,
 6112            snippet,
 6113            replace_range,
 6114        } = process_completion_for_edit(
 6115            &completion,
 6116            intent,
 6117            &buffer_handle,
 6118            &completions_menu.initial_position.text_anchor,
 6119            cx,
 6120        );
 6121
 6122        let buffer = buffer_handle.read(cx);
 6123        let snapshot = self.buffer.read(cx).snapshot(cx);
 6124        let newest_anchor = self.selections.newest_anchor();
 6125        let replace_range_multibuffer = {
 6126            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6127            excerpt.map_range_from_buffer(replace_range.clone())
 6128        };
 6129        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6130            return None;
 6131        }
 6132
 6133        let old_text = buffer
 6134            .text_for_range(replace_range.clone())
 6135            .collect::<String>();
 6136        let lookbehind = newest_anchor
 6137            .start
 6138            .text_anchor
 6139            .to_offset(buffer)
 6140            .saturating_sub(replace_range.start.0);
 6141        let lookahead = replace_range
 6142            .end
 6143            .0
 6144            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6145        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6146        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6147
 6148        let selections = self
 6149            .selections
 6150            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6151        let mut ranges = Vec::new();
 6152        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6153
 6154        for selection in &selections {
 6155            let range = if selection.id == newest_anchor.id {
 6156                replace_range_multibuffer.clone()
 6157            } else {
 6158                let mut range = selection.range();
 6159
 6160                // if prefix is present, don't duplicate it
 6161                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6162                    range.start = range.start.saturating_sub_usize(lookbehind);
 6163
 6164                    // if suffix is also present, mimic the newest cursor and replace it
 6165                    if selection.id != newest_anchor.id
 6166                        && snapshot.contains_str_at(range.end, suffix)
 6167                    {
 6168                        range.end += lookahead;
 6169                    }
 6170                }
 6171                range
 6172            };
 6173
 6174            ranges.push(range.clone());
 6175
 6176            if !self.linked_edit_ranges.is_empty() {
 6177                let start_anchor = snapshot.anchor_before(range.start);
 6178                let end_anchor = snapshot.anchor_after(range.end);
 6179                if let Some(ranges) = self
 6180                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6181                {
 6182                    for (buffer, edits) in ranges {
 6183                        linked_edits
 6184                            .entry(buffer.clone())
 6185                            .or_default()
 6186                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6187                    }
 6188                }
 6189            }
 6190        }
 6191
 6192        let common_prefix_len = old_text
 6193            .chars()
 6194            .zip(new_text.chars())
 6195            .take_while(|(a, b)| a == b)
 6196            .map(|(a, _)| a.len_utf8())
 6197            .sum::<usize>();
 6198
 6199        cx.emit(EditorEvent::InputHandled {
 6200            utf16_range_to_replace: None,
 6201            text: new_text[common_prefix_len..].into(),
 6202        });
 6203
 6204        self.transact(window, cx, |editor, window, cx| {
 6205            if let Some(mut snippet) = snippet {
 6206                snippet.text = new_text.to_string();
 6207                editor
 6208                    .insert_snippet(&ranges, snippet, window, cx)
 6209                    .log_err();
 6210            } else {
 6211                editor.buffer.update(cx, |multi_buffer, cx| {
 6212                    let auto_indent = match completion.insert_text_mode {
 6213                        Some(InsertTextMode::AS_IS) => None,
 6214                        _ => editor.autoindent_mode.clone(),
 6215                    };
 6216                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6217                    multi_buffer.edit(edits, auto_indent, cx);
 6218                });
 6219            }
 6220            for (buffer, edits) in linked_edits {
 6221                buffer.update(cx, |buffer, cx| {
 6222                    let snapshot = buffer.snapshot();
 6223                    let edits = edits
 6224                        .into_iter()
 6225                        .map(|(range, text)| {
 6226                            use text::ToPoint as TP;
 6227                            let end_point = TP::to_point(&range.end, &snapshot);
 6228                            let start_point = TP::to_point(&range.start, &snapshot);
 6229                            (start_point..end_point, text)
 6230                        })
 6231                        .sorted_by_key(|(range, _)| range.start);
 6232                    buffer.edit(edits, None, cx);
 6233                })
 6234            }
 6235
 6236            editor.refresh_edit_prediction(true, false, window, cx);
 6237        });
 6238        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6239
 6240        let show_new_completions_on_confirm = completion
 6241            .confirm
 6242            .as_ref()
 6243            .is_some_and(|confirm| confirm(intent, window, cx));
 6244        if show_new_completions_on_confirm {
 6245            self.open_or_update_completions_menu(None, None, false, window, cx);
 6246        }
 6247
 6248        let provider = self.completion_provider.as_ref()?;
 6249
 6250        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6251        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6252            let CompletionSource::Lsp {
 6253                lsp_completion,
 6254                server_id,
 6255                ..
 6256            } = &completion.source
 6257            else {
 6258                return None;
 6259            };
 6260            let lsp_command = lsp_completion.command.as_ref()?;
 6261            let available_commands = lsp_store
 6262                .read(cx)
 6263                .lsp_server_capabilities
 6264                .get(server_id)
 6265                .and_then(|server_capabilities| {
 6266                    server_capabilities
 6267                        .execute_command_provider
 6268                        .as_ref()
 6269                        .map(|options| options.commands.as_slice())
 6270                })?;
 6271            if available_commands.contains(&lsp_command.command) {
 6272                Some(CodeAction {
 6273                    server_id: *server_id,
 6274                    range: language::Anchor::MIN..language::Anchor::MIN,
 6275                    lsp_action: LspAction::Command(lsp_command.clone()),
 6276                    resolved: false,
 6277                })
 6278            } else {
 6279                None
 6280            }
 6281        });
 6282
 6283        drop(completion);
 6284        let apply_edits = provider.apply_additional_edits_for_completion(
 6285            buffer_handle.clone(),
 6286            completions_menu.completions.clone(),
 6287            candidate_id,
 6288            true,
 6289            cx,
 6290        );
 6291
 6292        let editor_settings = EditorSettings::get_global(cx);
 6293        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6294            // After the code completion is finished, users often want to know what signatures are needed.
 6295            // so we should automatically call signature_help
 6296            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6297        }
 6298
 6299        Some(cx.spawn_in(window, async move |editor, cx| {
 6300            apply_edits.await?;
 6301
 6302            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6303                let title = command.lsp_action.title().to_owned();
 6304                let project_transaction = lsp_store
 6305                    .update(cx, |lsp_store, cx| {
 6306                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6307                    })?
 6308                    .await
 6309                    .context("applying post-completion command")?;
 6310                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6311                    Self::open_project_transaction(
 6312                        &editor,
 6313                        workspace.downgrade(),
 6314                        project_transaction,
 6315                        title,
 6316                        cx,
 6317                    )
 6318                    .await?;
 6319                }
 6320            }
 6321
 6322            Ok(())
 6323        }))
 6324    }
 6325
 6326    pub fn toggle_code_actions(
 6327        &mut self,
 6328        action: &ToggleCodeActions,
 6329        window: &mut Window,
 6330        cx: &mut Context<Self>,
 6331    ) {
 6332        let quick_launch = action.quick_launch;
 6333        let mut context_menu = self.context_menu.borrow_mut();
 6334        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6335            if code_actions.deployed_from == action.deployed_from {
 6336                // Toggle if we're selecting the same one
 6337                *context_menu = None;
 6338                cx.notify();
 6339                return;
 6340            } else {
 6341                // Otherwise, clear it and start a new one
 6342                *context_menu = None;
 6343                cx.notify();
 6344            }
 6345        }
 6346        drop(context_menu);
 6347        let snapshot = self.snapshot(window, cx);
 6348        let deployed_from = action.deployed_from.clone();
 6349        let action = action.clone();
 6350        self.completion_tasks.clear();
 6351        self.discard_edit_prediction(false, cx);
 6352
 6353        let multibuffer_point = match &action.deployed_from {
 6354            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6355                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6356            }
 6357            _ => self
 6358                .selections
 6359                .newest::<Point>(&snapshot.display_snapshot)
 6360                .head(),
 6361        };
 6362        let Some((buffer, buffer_row)) = snapshot
 6363            .buffer_snapshot()
 6364            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6365            .and_then(|(buffer_snapshot, range)| {
 6366                self.buffer()
 6367                    .read(cx)
 6368                    .buffer(buffer_snapshot.remote_id())
 6369                    .map(|buffer| (buffer, range.start.row))
 6370            })
 6371        else {
 6372            return;
 6373        };
 6374        let buffer_id = buffer.read(cx).remote_id();
 6375        let tasks = self
 6376            .tasks
 6377            .get(&(buffer_id, buffer_row))
 6378            .map(|t| Arc::new(t.to_owned()));
 6379
 6380        if !self.focus_handle.is_focused(window) {
 6381            return;
 6382        }
 6383        let project = self.project.clone();
 6384
 6385        let code_actions_task = match deployed_from {
 6386            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6387            _ => self.code_actions(buffer_row, window, cx),
 6388        };
 6389
 6390        let runnable_task = match deployed_from {
 6391            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6392            _ => {
 6393                let mut task_context_task = Task::ready(None);
 6394                if let Some(tasks) = &tasks
 6395                    && let Some(project) = project
 6396                {
 6397                    task_context_task =
 6398                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6399                }
 6400
 6401                cx.spawn_in(window, {
 6402                    let buffer = buffer.clone();
 6403                    async move |editor, cx| {
 6404                        let task_context = task_context_task.await;
 6405
 6406                        let resolved_tasks =
 6407                            tasks
 6408                                .zip(task_context.clone())
 6409                                .map(|(tasks, task_context)| ResolvedTasks {
 6410                                    templates: tasks.resolve(&task_context).collect(),
 6411                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6412                                        multibuffer_point.row,
 6413                                        tasks.column,
 6414                                    )),
 6415                                });
 6416                        let debug_scenarios = editor
 6417                            .update(cx, |editor, cx| {
 6418                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6419                            })?
 6420                            .await;
 6421                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6422                    }
 6423                })
 6424            }
 6425        };
 6426
 6427        cx.spawn_in(window, async move |editor, cx| {
 6428            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6429            let code_actions = code_actions_task.await;
 6430            let spawn_straight_away = quick_launch
 6431                && resolved_tasks
 6432                    .as_ref()
 6433                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6434                && code_actions
 6435                    .as_ref()
 6436                    .is_none_or(|actions| actions.is_empty())
 6437                && debug_scenarios.is_empty();
 6438
 6439            editor.update_in(cx, |editor, window, cx| {
 6440                crate::hover_popover::hide_hover(editor, cx);
 6441                let actions = CodeActionContents::new(
 6442                    resolved_tasks,
 6443                    code_actions,
 6444                    debug_scenarios,
 6445                    task_context.unwrap_or_default(),
 6446                );
 6447
 6448                // Don't show the menu if there are no actions available
 6449                if actions.is_empty() {
 6450                    cx.notify();
 6451                    return Task::ready(Ok(()));
 6452                }
 6453
 6454                *editor.context_menu.borrow_mut() =
 6455                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6456                        buffer,
 6457                        actions,
 6458                        selected_item: Default::default(),
 6459                        scroll_handle: UniformListScrollHandle::default(),
 6460                        deployed_from,
 6461                    }));
 6462                cx.notify();
 6463                if spawn_straight_away
 6464                    && let Some(task) = editor.confirm_code_action(
 6465                        &ConfirmCodeAction { item_ix: Some(0) },
 6466                        window,
 6467                        cx,
 6468                    )
 6469                {
 6470                    return task;
 6471                }
 6472
 6473                Task::ready(Ok(()))
 6474            })
 6475        })
 6476        .detach_and_log_err(cx);
 6477    }
 6478
 6479    fn debug_scenarios(
 6480        &mut self,
 6481        resolved_tasks: &Option<ResolvedTasks>,
 6482        buffer: &Entity<Buffer>,
 6483        cx: &mut App,
 6484    ) -> Task<Vec<task::DebugScenario>> {
 6485        maybe!({
 6486            let project = self.project()?;
 6487            let dap_store = project.read(cx).dap_store();
 6488            let mut scenarios = vec![];
 6489            let resolved_tasks = resolved_tasks.as_ref()?;
 6490            let buffer = buffer.read(cx);
 6491            let language = buffer.language()?;
 6492            let file = buffer.file();
 6493            let debug_adapter = language_settings(language.name().into(), file, cx)
 6494                .debuggers
 6495                .first()
 6496                .map(SharedString::from)
 6497                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6498
 6499            dap_store.update(cx, |dap_store, cx| {
 6500                for (_, task) in &resolved_tasks.templates {
 6501                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6502                        task.original_task().clone(),
 6503                        debug_adapter.clone().into(),
 6504                        task.display_label().to_owned().into(),
 6505                        cx,
 6506                    );
 6507                    scenarios.push(maybe_scenario);
 6508                }
 6509            });
 6510            Some(cx.background_spawn(async move {
 6511                futures::future::join_all(scenarios)
 6512                    .await
 6513                    .into_iter()
 6514                    .flatten()
 6515                    .collect::<Vec<_>>()
 6516            }))
 6517        })
 6518        .unwrap_or_else(|| Task::ready(vec![]))
 6519    }
 6520
 6521    fn code_actions(
 6522        &mut self,
 6523        buffer_row: u32,
 6524        window: &mut Window,
 6525        cx: &mut Context<Self>,
 6526    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6527        let mut task = self.code_actions_task.take();
 6528        cx.spawn_in(window, async move |editor, cx| {
 6529            while let Some(prev_task) = task {
 6530                prev_task.await.log_err();
 6531                task = editor
 6532                    .update(cx, |this, _| this.code_actions_task.take())
 6533                    .ok()?;
 6534            }
 6535
 6536            editor
 6537                .update(cx, |editor, cx| {
 6538                    editor
 6539                        .available_code_actions
 6540                        .clone()
 6541                        .and_then(|(location, code_actions)| {
 6542                            let snapshot = location.buffer.read(cx).snapshot();
 6543                            let point_range = location.range.to_point(&snapshot);
 6544                            let point_range = point_range.start.row..=point_range.end.row;
 6545                            if point_range.contains(&buffer_row) {
 6546                                Some(code_actions)
 6547                            } else {
 6548                                None
 6549                            }
 6550                        })
 6551                })
 6552                .ok()
 6553                .flatten()
 6554        })
 6555    }
 6556
 6557    pub fn confirm_code_action(
 6558        &mut self,
 6559        action: &ConfirmCodeAction,
 6560        window: &mut Window,
 6561        cx: &mut Context<Self>,
 6562    ) -> Option<Task<Result<()>>> {
 6563        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6564
 6565        let actions_menu =
 6566            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6567                menu
 6568            } else {
 6569                return None;
 6570            };
 6571
 6572        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6573        let action = actions_menu.actions.get(action_ix)?;
 6574        let title = action.label();
 6575        let buffer = actions_menu.buffer;
 6576        let workspace = self.workspace()?;
 6577
 6578        match action {
 6579            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6580                workspace.update(cx, |workspace, cx| {
 6581                    workspace.schedule_resolved_task(
 6582                        task_source_kind,
 6583                        resolved_task,
 6584                        false,
 6585                        window,
 6586                        cx,
 6587                    );
 6588
 6589                    Some(Task::ready(Ok(())))
 6590                })
 6591            }
 6592            CodeActionsItem::CodeAction {
 6593                excerpt_id,
 6594                action,
 6595                provider,
 6596            } => {
 6597                let apply_code_action =
 6598                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6599                let workspace = workspace.downgrade();
 6600                Some(cx.spawn_in(window, async move |editor, cx| {
 6601                    let project_transaction = apply_code_action.await?;
 6602                    Self::open_project_transaction(
 6603                        &editor,
 6604                        workspace,
 6605                        project_transaction,
 6606                        title,
 6607                        cx,
 6608                    )
 6609                    .await
 6610                }))
 6611            }
 6612            CodeActionsItem::DebugScenario(scenario) => {
 6613                let context = actions_menu.actions.context;
 6614
 6615                workspace.update(cx, |workspace, cx| {
 6616                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6617                    workspace.start_debug_session(
 6618                        scenario,
 6619                        context,
 6620                        Some(buffer),
 6621                        None,
 6622                        window,
 6623                        cx,
 6624                    );
 6625                });
 6626                Some(Task::ready(Ok(())))
 6627            }
 6628        }
 6629    }
 6630
 6631    fn open_transaction_for_hidden_buffers(
 6632        workspace: Entity<Workspace>,
 6633        transaction: ProjectTransaction,
 6634        title: String,
 6635        window: &mut Window,
 6636        cx: &mut Context<Self>,
 6637    ) {
 6638        if transaction.0.is_empty() {
 6639            return;
 6640        }
 6641
 6642        let edited_buffers_already_open = {
 6643            let other_editors: Vec<Entity<Editor>> = workspace
 6644                .read(cx)
 6645                .panes()
 6646                .iter()
 6647                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 6648                .filter(|editor| editor.entity_id() != cx.entity_id())
 6649                .collect();
 6650
 6651            transaction.0.keys().all(|buffer| {
 6652                other_editors.iter().any(|editor| {
 6653                    let multi_buffer = editor.read(cx).buffer();
 6654                    multi_buffer.read(cx).is_singleton()
 6655                        && multi_buffer
 6656                            .read(cx)
 6657                            .as_singleton()
 6658                            .map_or(false, |singleton| {
 6659                                singleton.entity_id() == buffer.entity_id()
 6660                            })
 6661                })
 6662            })
 6663        };
 6664        if !edited_buffers_already_open {
 6665            let workspace = workspace.downgrade();
 6666            cx.defer_in(window, move |_, window, cx| {
 6667                cx.spawn_in(window, async move |editor, cx| {
 6668                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 6669                        .await
 6670                        .ok()
 6671                })
 6672                .detach();
 6673            });
 6674        }
 6675    }
 6676
 6677    pub async fn open_project_transaction(
 6678        editor: &WeakEntity<Editor>,
 6679        workspace: WeakEntity<Workspace>,
 6680        transaction: ProjectTransaction,
 6681        title: String,
 6682        cx: &mut AsyncWindowContext,
 6683    ) -> Result<()> {
 6684        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6685        cx.update(|_, cx| {
 6686            entries.sort_unstable_by_key(|(buffer, _)| {
 6687                buffer.read(cx).file().map(|f| f.path().clone())
 6688            });
 6689        })?;
 6690        if entries.is_empty() {
 6691            return Ok(());
 6692        }
 6693
 6694        // If the project transaction's edits are all contained within this editor, then
 6695        // avoid opening a new editor to display them.
 6696
 6697        if let [(buffer, transaction)] = &*entries {
 6698            let excerpt = editor.update(cx, |editor, cx| {
 6699                editor
 6700                    .buffer()
 6701                    .read(cx)
 6702                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6703            })?;
 6704            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6705                && excerpted_buffer == *buffer
 6706            {
 6707                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6708                    let excerpt_range = excerpt_range.to_offset(buffer);
 6709                    buffer
 6710                        .edited_ranges_for_transaction::<usize>(transaction)
 6711                        .all(|range| {
 6712                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6713                        })
 6714                })?;
 6715
 6716                if all_edits_within_excerpt {
 6717                    return Ok(());
 6718                }
 6719            }
 6720        }
 6721
 6722        let mut ranges_to_highlight = Vec::new();
 6723        let excerpt_buffer = cx.new(|cx| {
 6724            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6725            for (buffer_handle, transaction) in &entries {
 6726                let edited_ranges = buffer_handle
 6727                    .read(cx)
 6728                    .edited_ranges_for_transaction::<Point>(transaction)
 6729                    .collect::<Vec<_>>();
 6730                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6731                    PathKey::for_buffer(buffer_handle, cx),
 6732                    buffer_handle.clone(),
 6733                    edited_ranges,
 6734                    multibuffer_context_lines(cx),
 6735                    cx,
 6736                );
 6737
 6738                ranges_to_highlight.extend(ranges);
 6739            }
 6740            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6741            multibuffer
 6742        })?;
 6743
 6744        workspace.update_in(cx, |workspace, window, cx| {
 6745            let project = workspace.project().clone();
 6746            let editor =
 6747                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6748            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6749            editor.update(cx, |editor, cx| {
 6750                editor.highlight_background::<Self>(
 6751                    &ranges_to_highlight,
 6752                    |_, theme| theme.colors().editor_highlighted_line_background,
 6753                    cx,
 6754                );
 6755            });
 6756        })?;
 6757
 6758        Ok(())
 6759    }
 6760
 6761    pub fn clear_code_action_providers(&mut self) {
 6762        self.code_action_providers.clear();
 6763        self.available_code_actions.take();
 6764    }
 6765
 6766    pub fn add_code_action_provider(
 6767        &mut self,
 6768        provider: Rc<dyn CodeActionProvider>,
 6769        window: &mut Window,
 6770        cx: &mut Context<Self>,
 6771    ) {
 6772        if self
 6773            .code_action_providers
 6774            .iter()
 6775            .any(|existing_provider| existing_provider.id() == provider.id())
 6776        {
 6777            return;
 6778        }
 6779
 6780        self.code_action_providers.push(provider);
 6781        self.refresh_code_actions(window, cx);
 6782    }
 6783
 6784    pub fn remove_code_action_provider(
 6785        &mut self,
 6786        id: Arc<str>,
 6787        window: &mut Window,
 6788        cx: &mut Context<Self>,
 6789    ) {
 6790        self.code_action_providers
 6791            .retain(|provider| provider.id() != id);
 6792        self.refresh_code_actions(window, cx);
 6793    }
 6794
 6795    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6796        !self.code_action_providers.is_empty()
 6797            && EditorSettings::get_global(cx).toolbar.code_actions
 6798    }
 6799
 6800    pub fn has_available_code_actions(&self) -> bool {
 6801        self.available_code_actions
 6802            .as_ref()
 6803            .is_some_and(|(_, actions)| !actions.is_empty())
 6804    }
 6805
 6806    fn render_inline_code_actions(
 6807        &self,
 6808        icon_size: ui::IconSize,
 6809        display_row: DisplayRow,
 6810        is_active: bool,
 6811        cx: &mut Context<Self>,
 6812    ) -> AnyElement {
 6813        let show_tooltip = !self.context_menu_visible();
 6814        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6815            .icon_size(icon_size)
 6816            .shape(ui::IconButtonShape::Square)
 6817            .icon_color(ui::Color::Hidden)
 6818            .toggle_state(is_active)
 6819            .when(show_tooltip, |this| {
 6820                this.tooltip({
 6821                    let focus_handle = self.focus_handle.clone();
 6822                    move |_window, cx| {
 6823                        Tooltip::for_action_in(
 6824                            "Toggle Code Actions",
 6825                            &ToggleCodeActions {
 6826                                deployed_from: None,
 6827                                quick_launch: false,
 6828                            },
 6829                            &focus_handle,
 6830                            cx,
 6831                        )
 6832                    }
 6833                })
 6834            })
 6835            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6836                window.focus(&editor.focus_handle(cx), cx);
 6837                editor.toggle_code_actions(
 6838                    &crate::actions::ToggleCodeActions {
 6839                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6840                            display_row,
 6841                        )),
 6842                        quick_launch: false,
 6843                    },
 6844                    window,
 6845                    cx,
 6846                );
 6847            }))
 6848            .into_any_element()
 6849    }
 6850
 6851    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6852        &self.context_menu
 6853    }
 6854
 6855    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6856        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6857            cx.background_executor()
 6858                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6859                .await;
 6860
 6861            let (start_buffer, start, _, end, newest_selection) = this
 6862                .update(cx, |this, cx| {
 6863                    let newest_selection = this.selections.newest_anchor().clone();
 6864                    if newest_selection.head().diff_base_anchor.is_some() {
 6865                        return None;
 6866                    }
 6867                    let display_snapshot = this.display_snapshot(cx);
 6868                    let newest_selection_adjusted =
 6869                        this.selections.newest_adjusted(&display_snapshot);
 6870                    let buffer = this.buffer.read(cx);
 6871
 6872                    let (start_buffer, start) =
 6873                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6874                    let (end_buffer, end) =
 6875                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6876
 6877                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6878                })?
 6879                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6880                .context(
 6881                    "Expected selection to lie in a single buffer when refreshing code actions",
 6882                )?;
 6883            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6884                let providers = this.code_action_providers.clone();
 6885                let tasks = this
 6886                    .code_action_providers
 6887                    .iter()
 6888                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6889                    .collect::<Vec<_>>();
 6890                (providers, tasks)
 6891            })?;
 6892
 6893            let mut actions = Vec::new();
 6894            for (provider, provider_actions) in
 6895                providers.into_iter().zip(future::join_all(tasks).await)
 6896            {
 6897                if let Some(provider_actions) = provider_actions.log_err() {
 6898                    actions.extend(provider_actions.into_iter().map(|action| {
 6899                        AvailableCodeAction {
 6900                            excerpt_id: newest_selection.start.excerpt_id,
 6901                            action,
 6902                            provider: provider.clone(),
 6903                        }
 6904                    }));
 6905                }
 6906            }
 6907
 6908            this.update(cx, |this, cx| {
 6909                this.available_code_actions = if actions.is_empty() {
 6910                    None
 6911                } else {
 6912                    Some((
 6913                        Location {
 6914                            buffer: start_buffer,
 6915                            range: start..end,
 6916                        },
 6917                        actions.into(),
 6918                    ))
 6919                };
 6920                cx.notify();
 6921            })
 6922        }));
 6923    }
 6924
 6925    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6926        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6927            self.show_git_blame_inline = false;
 6928
 6929            self.show_git_blame_inline_delay_task =
 6930                Some(cx.spawn_in(window, async move |this, cx| {
 6931                    cx.background_executor().timer(delay).await;
 6932
 6933                    this.update(cx, |this, cx| {
 6934                        this.show_git_blame_inline = true;
 6935                        cx.notify();
 6936                    })
 6937                    .log_err();
 6938                }));
 6939        }
 6940    }
 6941
 6942    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6943        let snapshot = self.snapshot(window, cx);
 6944        let cursor = self
 6945            .selections
 6946            .newest::<Point>(&snapshot.display_snapshot)
 6947            .head();
 6948        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6949        else {
 6950            return;
 6951        };
 6952
 6953        if self.blame.is_none() {
 6954            self.start_git_blame(true, window, cx);
 6955        }
 6956        let Some(blame) = self.blame.as_ref() else {
 6957            return;
 6958        };
 6959
 6960        let row_info = RowInfo {
 6961            buffer_id: Some(buffer.remote_id()),
 6962            buffer_row: Some(point.row),
 6963            ..Default::default()
 6964        };
 6965        let Some((buffer, blame_entry)) = blame
 6966            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6967            .flatten()
 6968        else {
 6969            return;
 6970        };
 6971
 6972        let anchor = self.selections.newest_anchor().head();
 6973        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 6974        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6975            self.show_blame_popover(
 6976                buffer,
 6977                &blame_entry,
 6978                position + last_bounds.origin,
 6979                true,
 6980                cx,
 6981            );
 6982        };
 6983    }
 6984
 6985    fn show_blame_popover(
 6986        &mut self,
 6987        buffer: BufferId,
 6988        blame_entry: &BlameEntry,
 6989        position: gpui::Point<Pixels>,
 6990        ignore_timeout: bool,
 6991        cx: &mut Context<Self>,
 6992    ) {
 6993        if let Some(state) = &mut self.inline_blame_popover {
 6994            state.hide_task.take();
 6995        } else {
 6996            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6997            let blame_entry = blame_entry.clone();
 6998            let show_task = cx.spawn(async move |editor, cx| {
 6999                if !ignore_timeout {
 7000                    cx.background_executor()
 7001                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 7002                        .await;
 7003                }
 7004                editor
 7005                    .update(cx, |editor, cx| {
 7006                        editor.inline_blame_popover_show_task.take();
 7007                        let Some(blame) = editor.blame.as_ref() else {
 7008                            return;
 7009                        };
 7010                        let blame = blame.read(cx);
 7011                        let details = blame.details_for_entry(buffer, &blame_entry);
 7012                        let markdown = cx.new(|cx| {
 7013                            Markdown::new(
 7014                                details
 7015                                    .as_ref()
 7016                                    .map(|message| message.message.clone())
 7017                                    .unwrap_or_default(),
 7018                                None,
 7019                                None,
 7020                                cx,
 7021                            )
 7022                        });
 7023                        editor.inline_blame_popover = Some(InlineBlamePopover {
 7024                            position,
 7025                            hide_task: None,
 7026                            popover_bounds: None,
 7027                            popover_state: InlineBlamePopoverState {
 7028                                scroll_handle: ScrollHandle::new(),
 7029                                commit_message: details,
 7030                                markdown,
 7031                            },
 7032                            keyboard_grace: ignore_timeout,
 7033                        });
 7034                        cx.notify();
 7035                    })
 7036                    .ok();
 7037            });
 7038            self.inline_blame_popover_show_task = Some(show_task);
 7039        }
 7040    }
 7041
 7042    pub fn has_mouse_context_menu(&self) -> bool {
 7043        self.mouse_context_menu.is_some()
 7044    }
 7045
 7046    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 7047        self.inline_blame_popover_show_task.take();
 7048        if let Some(state) = &mut self.inline_blame_popover {
 7049            let hide_task = cx.spawn(async move |editor, cx| {
 7050                if !ignore_timeout {
 7051                    cx.background_executor()
 7052                        .timer(std::time::Duration::from_millis(100))
 7053                        .await;
 7054                }
 7055                editor
 7056                    .update(cx, |editor, cx| {
 7057                        editor.inline_blame_popover.take();
 7058                        cx.notify();
 7059                    })
 7060                    .ok();
 7061            });
 7062            state.hide_task = Some(hide_task);
 7063            true
 7064        } else {
 7065            false
 7066        }
 7067    }
 7068
 7069    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7070        if self.pending_rename.is_some() {
 7071            return None;
 7072        }
 7073
 7074        let provider = self.semantics_provider.clone()?;
 7075        let buffer = self.buffer.read(cx);
 7076        let newest_selection = self.selections.newest_anchor().clone();
 7077        let cursor_position = newest_selection.head();
 7078        let (cursor_buffer, cursor_buffer_position) =
 7079            buffer.text_anchor_for_position(cursor_position, cx)?;
 7080        let (tail_buffer, tail_buffer_position) =
 7081            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7082        if cursor_buffer != tail_buffer {
 7083            return None;
 7084        }
 7085
 7086        let snapshot = cursor_buffer.read(cx).snapshot();
 7087        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7088        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7089        if start_word_range != end_word_range {
 7090            self.document_highlights_task.take();
 7091            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 7092            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 7093            return None;
 7094        }
 7095
 7096        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7097        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7098            cx.background_executor()
 7099                .timer(Duration::from_millis(debounce))
 7100                .await;
 7101
 7102            let highlights = if let Some(highlights) = cx
 7103                .update(|cx| {
 7104                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7105                })
 7106                .ok()
 7107                .flatten()
 7108            {
 7109                highlights.await.log_err()
 7110            } else {
 7111                None
 7112            };
 7113
 7114            if let Some(highlights) = highlights {
 7115                this.update(cx, |this, cx| {
 7116                    if this.pending_rename.is_some() {
 7117                        return;
 7118                    }
 7119
 7120                    let buffer = this.buffer.read(cx);
 7121                    if buffer
 7122                        .text_anchor_for_position(cursor_position, cx)
 7123                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7124                    {
 7125                        return;
 7126                    }
 7127
 7128                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7129                    let mut write_ranges = Vec::new();
 7130                    let mut read_ranges = Vec::new();
 7131                    for highlight in highlights {
 7132                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7133                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7134                        {
 7135                            let start = highlight
 7136                                .range
 7137                                .start
 7138                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7139                            let end = highlight
 7140                                .range
 7141                                .end
 7142                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7143                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7144                                continue;
 7145                            }
 7146
 7147                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7148                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7149                                write_ranges.push(range);
 7150                            } else {
 7151                                read_ranges.push(range);
 7152                            }
 7153                        }
 7154                    }
 7155
 7156                    this.highlight_background::<DocumentHighlightRead>(
 7157                        &read_ranges,
 7158                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7159                        cx,
 7160                    );
 7161                    this.highlight_background::<DocumentHighlightWrite>(
 7162                        &write_ranges,
 7163                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7164                        cx,
 7165                    );
 7166                    cx.notify();
 7167                })
 7168                .log_err();
 7169            }
 7170        }));
 7171        None
 7172    }
 7173
 7174    fn prepare_highlight_query_from_selection(
 7175        &mut self,
 7176        window: &Window,
 7177        cx: &mut Context<Editor>,
 7178    ) -> Option<(String, Range<Anchor>)> {
 7179        if matches!(self.mode, EditorMode::SingleLine) {
 7180            return None;
 7181        }
 7182        if !EditorSettings::get_global(cx).selection_highlight {
 7183            return None;
 7184        }
 7185        if self.selections.count() != 1 || self.selections.line_mode() {
 7186            return None;
 7187        }
 7188        let snapshot = self.snapshot(window, cx);
 7189        let selection = self.selections.newest::<Point>(&snapshot);
 7190        // If the selection spans multiple rows OR it is empty
 7191        if selection.start.row != selection.end.row
 7192            || selection.start.column == selection.end.column
 7193        {
 7194            return None;
 7195        }
 7196        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7197        let query = snapshot
 7198            .buffer_snapshot()
 7199            .text_for_range(selection_anchor_range.clone())
 7200            .collect::<String>();
 7201        if query.trim().is_empty() {
 7202            return None;
 7203        }
 7204        Some((query, selection_anchor_range))
 7205    }
 7206
 7207    #[ztracing::instrument(skip_all)]
 7208    fn update_selection_occurrence_highlights(
 7209        &mut self,
 7210        query_text: String,
 7211        query_range: Range<Anchor>,
 7212        multi_buffer_range_to_query: Range<Point>,
 7213        use_debounce: bool,
 7214        window: &mut Window,
 7215        cx: &mut Context<Editor>,
 7216    ) -> Task<()> {
 7217        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7218        cx.spawn_in(window, async move |editor, cx| {
 7219            if use_debounce {
 7220                cx.background_executor()
 7221                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7222                    .await;
 7223            }
 7224            let match_task = cx.background_spawn(async move {
 7225                let buffer_ranges = multi_buffer_snapshot
 7226                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7227                    .into_iter()
 7228                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7229                let mut match_ranges = Vec::new();
 7230                let Ok(regex) = project::search::SearchQuery::text(
 7231                    query_text.clone(),
 7232                    false,
 7233                    false,
 7234                    false,
 7235                    Default::default(),
 7236                    Default::default(),
 7237                    false,
 7238                    None,
 7239                ) else {
 7240                    return Vec::default();
 7241                };
 7242                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7243                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7244                    match_ranges.extend(
 7245                        regex
 7246                            .search(
 7247                                buffer_snapshot,
 7248                                Some(search_range.start.0..search_range.end.0),
 7249                            )
 7250                            .await
 7251                            .into_iter()
 7252                            .filter_map(|match_range| {
 7253                                let match_start = buffer_snapshot
 7254                                    .anchor_after(search_range.start + match_range.start);
 7255                                let match_end = buffer_snapshot
 7256                                    .anchor_before(search_range.start + match_range.end);
 7257                                let match_anchor_range =
 7258                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7259                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7260                            }),
 7261                    );
 7262                }
 7263                match_ranges
 7264            });
 7265            let match_ranges = match_task.await;
 7266            editor
 7267                .update_in(cx, |editor, _, cx| {
 7268                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7269                    if !match_ranges.is_empty() {
 7270                        editor.highlight_background::<SelectedTextHighlight>(
 7271                            &match_ranges,
 7272                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7273                            cx,
 7274                        )
 7275                    }
 7276                })
 7277                .log_err();
 7278        })
 7279    }
 7280
 7281    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7282        struct NewlineFold;
 7283        let type_id = std::any::TypeId::of::<NewlineFold>();
 7284        if !self.mode.is_single_line() {
 7285            return;
 7286        }
 7287        let snapshot = self.snapshot(window, cx);
 7288        if snapshot.buffer_snapshot().max_point().row == 0 {
 7289            return;
 7290        }
 7291        let task = cx.background_spawn(async move {
 7292            let new_newlines = snapshot
 7293                .buffer_chars_at(MultiBufferOffset(0))
 7294                .filter_map(|(c, i)| {
 7295                    if c == '\n' {
 7296                        Some(
 7297                            snapshot.buffer_snapshot().anchor_after(i)
 7298                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7299                        )
 7300                    } else {
 7301                        None
 7302                    }
 7303                })
 7304                .collect::<Vec<_>>();
 7305            let existing_newlines = snapshot
 7306                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7307                .filter_map(|fold| {
 7308                    if fold.placeholder.type_tag == Some(type_id) {
 7309                        Some(fold.range.start..fold.range.end)
 7310                    } else {
 7311                        None
 7312                    }
 7313                })
 7314                .collect::<Vec<_>>();
 7315
 7316            (new_newlines, existing_newlines)
 7317        });
 7318        self.folding_newlines = cx.spawn(async move |this, cx| {
 7319            let (new_newlines, existing_newlines) = task.await;
 7320            if new_newlines == existing_newlines {
 7321                return;
 7322            }
 7323            let placeholder = FoldPlaceholder {
 7324                render: Arc::new(move |_, _, cx| {
 7325                    div()
 7326                        .bg(cx.theme().status().hint_background)
 7327                        .border_b_1()
 7328                        .size_full()
 7329                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7330                        .border_color(cx.theme().status().hint)
 7331                        .child("\\n")
 7332                        .into_any()
 7333                }),
 7334                constrain_width: false,
 7335                merge_adjacent: false,
 7336                type_tag: Some(type_id),
 7337            };
 7338            let creases = new_newlines
 7339                .into_iter()
 7340                .map(|range| Crease::simple(range, placeholder.clone()))
 7341                .collect();
 7342            this.update(cx, |this, cx| {
 7343                this.display_map.update(cx, |display_map, cx| {
 7344                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7345                    display_map.fold(creases, cx);
 7346                });
 7347            })
 7348            .ok();
 7349        });
 7350    }
 7351
 7352    #[ztracing::instrument(skip_all)]
 7353    fn refresh_selected_text_highlights(
 7354        &mut self,
 7355        on_buffer_edit: bool,
 7356        window: &mut Window,
 7357        cx: &mut Context<Editor>,
 7358    ) {
 7359        let Some((query_text, query_range)) =
 7360            self.prepare_highlight_query_from_selection(window, cx)
 7361        else {
 7362            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7363            self.quick_selection_highlight_task.take();
 7364            self.debounced_selection_highlight_task.take();
 7365            return;
 7366        };
 7367        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7368        if on_buffer_edit
 7369            || self
 7370                .quick_selection_highlight_task
 7371                .as_ref()
 7372                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7373        {
 7374            let multi_buffer_visible_start = self
 7375                .scroll_manager
 7376                .anchor()
 7377                .anchor
 7378                .to_point(&multi_buffer_snapshot);
 7379            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7380                multi_buffer_visible_start
 7381                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7382                Bias::Left,
 7383            );
 7384            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7385            self.quick_selection_highlight_task = Some((
 7386                query_range.clone(),
 7387                self.update_selection_occurrence_highlights(
 7388                    query_text.clone(),
 7389                    query_range.clone(),
 7390                    multi_buffer_visible_range,
 7391                    false,
 7392                    window,
 7393                    cx,
 7394                ),
 7395            ));
 7396        }
 7397        if on_buffer_edit
 7398            || self
 7399                .debounced_selection_highlight_task
 7400                .as_ref()
 7401                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7402        {
 7403            let multi_buffer_start = multi_buffer_snapshot
 7404                .anchor_before(MultiBufferOffset(0))
 7405                .to_point(&multi_buffer_snapshot);
 7406            let multi_buffer_end = multi_buffer_snapshot
 7407                .anchor_after(multi_buffer_snapshot.len())
 7408                .to_point(&multi_buffer_snapshot);
 7409            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7410            self.debounced_selection_highlight_task = Some((
 7411                query_range.clone(),
 7412                self.update_selection_occurrence_highlights(
 7413                    query_text,
 7414                    query_range,
 7415                    multi_buffer_full_range,
 7416                    true,
 7417                    window,
 7418                    cx,
 7419                ),
 7420            ));
 7421        }
 7422    }
 7423
 7424    pub fn refresh_edit_prediction(
 7425        &mut self,
 7426        debounce: bool,
 7427        user_requested: bool,
 7428        window: &mut Window,
 7429        cx: &mut Context<Self>,
 7430    ) -> Option<()> {
 7431        if DisableAiSettings::get_global(cx).disable_ai {
 7432            return None;
 7433        }
 7434
 7435        let provider = self.edit_prediction_provider()?;
 7436        let cursor = self.selections.newest_anchor().head();
 7437        let (buffer, cursor_buffer_position) =
 7438            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7439
 7440        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7441            self.discard_edit_prediction(false, cx);
 7442            return None;
 7443        }
 7444
 7445        self.update_visible_edit_prediction(window, cx);
 7446
 7447        if !user_requested
 7448            && (!self.should_show_edit_predictions()
 7449                || !self.is_focused(window)
 7450                || buffer.read(cx).is_empty())
 7451        {
 7452            self.discard_edit_prediction(false, cx);
 7453            return None;
 7454        }
 7455
 7456        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7457        Some(())
 7458    }
 7459
 7460    fn show_edit_predictions_in_menu(&self) -> bool {
 7461        match self.edit_prediction_settings {
 7462            EditPredictionSettings::Disabled => false,
 7463            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7464        }
 7465    }
 7466
 7467    pub fn edit_predictions_enabled(&self) -> bool {
 7468        match self.edit_prediction_settings {
 7469            EditPredictionSettings::Disabled => false,
 7470            EditPredictionSettings::Enabled { .. } => true,
 7471        }
 7472    }
 7473
 7474    fn edit_prediction_requires_modifier(&self) -> bool {
 7475        match self.edit_prediction_settings {
 7476            EditPredictionSettings::Disabled => false,
 7477            EditPredictionSettings::Enabled {
 7478                preview_requires_modifier,
 7479                ..
 7480            } => preview_requires_modifier,
 7481        }
 7482    }
 7483
 7484    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7485        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7486            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7487            self.discard_edit_prediction(false, cx);
 7488        } else {
 7489            let selection = self.selections.newest_anchor();
 7490            let cursor = selection.head();
 7491
 7492            if let Some((buffer, cursor_buffer_position)) =
 7493                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7494            {
 7495                self.edit_prediction_settings =
 7496                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7497            }
 7498        }
 7499    }
 7500
 7501    fn edit_prediction_settings_at_position(
 7502        &self,
 7503        buffer: &Entity<Buffer>,
 7504        buffer_position: language::Anchor,
 7505        cx: &App,
 7506    ) -> EditPredictionSettings {
 7507        if !self.mode.is_full()
 7508            || !self.show_edit_predictions_override.unwrap_or(true)
 7509            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7510        {
 7511            return EditPredictionSettings::Disabled;
 7512        }
 7513
 7514        let buffer = buffer.read(cx);
 7515
 7516        let file = buffer.file();
 7517
 7518        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7519            return EditPredictionSettings::Disabled;
 7520        };
 7521
 7522        let by_provider = matches!(
 7523            self.menu_edit_predictions_policy,
 7524            MenuEditPredictionsPolicy::ByProvider
 7525        );
 7526
 7527        let show_in_menu = by_provider
 7528            && self
 7529                .edit_prediction_provider
 7530                .as_ref()
 7531                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7532
 7533        let preview_requires_modifier =
 7534            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7535
 7536        EditPredictionSettings::Enabled {
 7537            show_in_menu,
 7538            preview_requires_modifier,
 7539        }
 7540    }
 7541
 7542    fn should_show_edit_predictions(&self) -> bool {
 7543        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7544    }
 7545
 7546    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7547        matches!(
 7548            self.edit_prediction_preview,
 7549            EditPredictionPreview::Active { .. }
 7550        )
 7551    }
 7552
 7553    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7554        let cursor = self.selections.newest_anchor().head();
 7555        if let Some((buffer, cursor_position)) =
 7556            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7557        {
 7558            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7559        } else {
 7560            false
 7561        }
 7562    }
 7563
 7564    pub fn supports_minimap(&self, cx: &App) -> bool {
 7565        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7566    }
 7567
 7568    fn edit_predictions_enabled_in_buffer(
 7569        &self,
 7570        buffer: &Entity<Buffer>,
 7571        buffer_position: language::Anchor,
 7572        cx: &App,
 7573    ) -> bool {
 7574        maybe!({
 7575            if self.read_only(cx) {
 7576                return Some(false);
 7577            }
 7578            let provider = self.edit_prediction_provider()?;
 7579            if !provider.is_enabled(buffer, buffer_position, cx) {
 7580                return Some(false);
 7581            }
 7582            let buffer = buffer.read(cx);
 7583            let Some(file) = buffer.file() else {
 7584                return Some(true);
 7585            };
 7586            let settings = all_language_settings(Some(file), cx);
 7587            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7588        })
 7589        .unwrap_or(false)
 7590    }
 7591
 7592    pub fn show_edit_prediction(
 7593        &mut self,
 7594        _: &ShowEditPrediction,
 7595        window: &mut Window,
 7596        cx: &mut Context<Self>,
 7597    ) {
 7598        if !self.has_active_edit_prediction() {
 7599            self.refresh_edit_prediction(false, true, window, cx);
 7600            return;
 7601        }
 7602
 7603        self.update_visible_edit_prediction(window, cx);
 7604    }
 7605
 7606    pub fn display_cursor_names(
 7607        &mut self,
 7608        _: &DisplayCursorNames,
 7609        window: &mut Window,
 7610        cx: &mut Context<Self>,
 7611    ) {
 7612        self.show_cursor_names(window, cx);
 7613    }
 7614
 7615    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7616        self.show_cursor_names = true;
 7617        cx.notify();
 7618        cx.spawn_in(window, async move |this, cx| {
 7619            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7620            this.update(cx, |this, cx| {
 7621                this.show_cursor_names = false;
 7622                cx.notify()
 7623            })
 7624            .ok()
 7625        })
 7626        .detach();
 7627    }
 7628
 7629    pub fn accept_partial_edit_prediction(
 7630        &mut self,
 7631        granularity: EditPredictionGranularity,
 7632        window: &mut Window,
 7633        cx: &mut Context<Self>,
 7634    ) {
 7635        if self.show_edit_predictions_in_menu() {
 7636            self.hide_context_menu(window, cx);
 7637        }
 7638
 7639        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7640            return;
 7641        };
 7642
 7643        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 7644            return;
 7645        }
 7646
 7647        match &active_edit_prediction.completion {
 7648            EditPrediction::MoveWithin { target, .. } => {
 7649                let target = *target;
 7650
 7651                if matches!(granularity, EditPredictionGranularity::Full) {
 7652                    if let Some(position_map) = &self.last_position_map {
 7653                        let target_row = target.to_display_point(&position_map.snapshot).row();
 7654                        let is_visible = position_map.visible_row_range.contains(&target_row);
 7655
 7656                        if is_visible || !self.edit_prediction_requires_modifier() {
 7657                            self.unfold_ranges(&[target..target], true, false, cx);
 7658                            self.change_selections(
 7659                                SelectionEffects::scroll(Autoscroll::newest()),
 7660                                window,
 7661                                cx,
 7662                                |selections| {
 7663                                    selections.select_anchor_ranges([target..target]);
 7664                                },
 7665                            );
 7666                            self.clear_row_highlights::<EditPredictionPreview>();
 7667                            self.edit_prediction_preview
 7668                                .set_previous_scroll_position(None);
 7669                        } else {
 7670                            // Highlight and request scroll
 7671                            self.edit_prediction_preview
 7672                                .set_previous_scroll_position(Some(
 7673                                    position_map.snapshot.scroll_anchor,
 7674                                ));
 7675                            self.highlight_rows::<EditPredictionPreview>(
 7676                                target..target,
 7677                                cx.theme().colors().editor_highlighted_line_background,
 7678                                RowHighlightOptions {
 7679                                    autoscroll: true,
 7680                                    ..Default::default()
 7681                                },
 7682                                cx,
 7683                            );
 7684                            self.request_autoscroll(Autoscroll::fit(), cx);
 7685                        }
 7686                    }
 7687                } else {
 7688                    self.change_selections(
 7689                        SelectionEffects::scroll(Autoscroll::newest()),
 7690                        window,
 7691                        cx,
 7692                        |selections| {
 7693                            selections.select_anchor_ranges([target..target]);
 7694                        },
 7695                    );
 7696                }
 7697            }
 7698            EditPrediction::MoveOutside { snapshot, target } => {
 7699                if let Some(workspace) = self.workspace() {
 7700                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7701                        .detach_and_log_err(cx);
 7702                }
 7703            }
 7704            EditPrediction::Edit { edits, .. } => {
 7705                self.report_edit_prediction_event(
 7706                    active_edit_prediction.completion_id.clone(),
 7707                    true,
 7708                    cx,
 7709                );
 7710
 7711                match granularity {
 7712                    EditPredictionGranularity::Full => {
 7713                        if let Some(provider) = self.edit_prediction_provider() {
 7714                            provider.accept(cx);
 7715                        }
 7716
 7717                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7718                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7719                        let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7720
 7721                        self.buffer.update(cx, |buffer, cx| {
 7722                            buffer.edit(edits.iter().cloned(), None, cx)
 7723                        });
 7724
 7725                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7726                            s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7727                        });
 7728
 7729                        let selections = self.selections.disjoint_anchors_arc();
 7730                        if let Some(transaction_id_now) =
 7731                            self.buffer.read(cx).last_transaction_id(cx)
 7732                        {
 7733                            if transaction_id_prev != Some(transaction_id_now) {
 7734                                self.selection_history
 7735                                    .insert_transaction(transaction_id_now, selections);
 7736                            }
 7737                        }
 7738
 7739                        self.update_visible_edit_prediction(window, cx);
 7740                        if self.active_edit_prediction.is_none() {
 7741                            self.refresh_edit_prediction(true, true, window, cx);
 7742                        }
 7743                        cx.notify();
 7744                    }
 7745                    _ => {
 7746                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7747                        let cursor_offset = self
 7748                            .selections
 7749                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7750                            .head();
 7751
 7752                        let insertion = edits.iter().find_map(|(range, text)| {
 7753                            let range = range.to_offset(&snapshot);
 7754                            if range.is_empty() && range.start == cursor_offset {
 7755                                Some(text)
 7756                            } else {
 7757                                None
 7758                            }
 7759                        });
 7760
 7761                        if let Some(text) = insertion {
 7762                            let text_to_insert = match granularity {
 7763                                EditPredictionGranularity::Word => {
 7764                                    let mut partial = text
 7765                                        .chars()
 7766                                        .by_ref()
 7767                                        .take_while(|c| c.is_alphabetic())
 7768                                        .collect::<String>();
 7769                                    if partial.is_empty() {
 7770                                        partial = text
 7771                                            .chars()
 7772                                            .by_ref()
 7773                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7774                                            .collect::<String>();
 7775                                    }
 7776                                    partial
 7777                                }
 7778                                EditPredictionGranularity::Line => {
 7779                                    if let Some(line) = text.split_inclusive('\n').next() {
 7780                                        line.to_string()
 7781                                    } else {
 7782                                        text.to_string()
 7783                                    }
 7784                                }
 7785                                EditPredictionGranularity::Full => unreachable!(),
 7786                            };
 7787
 7788                            cx.emit(EditorEvent::InputHandled {
 7789                                utf16_range_to_replace: None,
 7790                                text: text_to_insert.clone().into(),
 7791                            });
 7792
 7793                            self.insert_with_autoindent_mode(&text_to_insert, None, window, cx);
 7794                            self.refresh_edit_prediction(true, true, window, cx);
 7795                            cx.notify();
 7796                        } else {
 7797                            self.accept_partial_edit_prediction(
 7798                                EditPredictionGranularity::Full,
 7799                                window,
 7800                                cx,
 7801                            );
 7802                        }
 7803                    }
 7804                }
 7805            }
 7806        }
 7807
 7808        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7809    }
 7810
 7811    pub fn accept_next_word_edit_prediction(
 7812        &mut self,
 7813        _: &AcceptNextWordEditPrediction,
 7814        window: &mut Window,
 7815        cx: &mut Context<Self>,
 7816    ) {
 7817        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 7818    }
 7819
 7820    pub fn accept_next_line_edit_prediction(
 7821        &mut self,
 7822        _: &AcceptNextLineEditPrediction,
 7823        window: &mut Window,
 7824        cx: &mut Context<Self>,
 7825    ) {
 7826        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 7827    }
 7828
 7829    pub fn accept_edit_prediction(
 7830        &mut self,
 7831        _: &AcceptEditPrediction,
 7832        window: &mut Window,
 7833        cx: &mut Context<Self>,
 7834    ) {
 7835        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 7836    }
 7837
 7838    fn discard_edit_prediction(
 7839        &mut self,
 7840        should_report_edit_prediction_event: bool,
 7841        cx: &mut Context<Self>,
 7842    ) -> bool {
 7843        if should_report_edit_prediction_event {
 7844            let completion_id = self
 7845                .active_edit_prediction
 7846                .as_ref()
 7847                .and_then(|active_completion| active_completion.completion_id.clone());
 7848
 7849            self.report_edit_prediction_event(completion_id, false, cx);
 7850        }
 7851
 7852        if let Some(provider) = self.edit_prediction_provider() {
 7853            provider.discard(cx);
 7854        }
 7855
 7856        self.take_active_edit_prediction(cx)
 7857    }
 7858
 7859    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7860        let Some(provider) = self.edit_prediction_provider() else {
 7861            return;
 7862        };
 7863
 7864        let Some((_, buffer, _)) = self
 7865            .buffer
 7866            .read(cx)
 7867            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7868        else {
 7869            return;
 7870        };
 7871
 7872        let extension = buffer
 7873            .read(cx)
 7874            .file()
 7875            .and_then(|file| Some(file.path().extension()?.to_string()));
 7876
 7877        let event_type = match accepted {
 7878            true => "Edit Prediction Accepted",
 7879            false => "Edit Prediction Discarded",
 7880        };
 7881        telemetry::event!(
 7882            event_type,
 7883            provider = provider.name(),
 7884            prediction_id = id,
 7885            suggestion_accepted = accepted,
 7886            file_extension = extension,
 7887        );
 7888    }
 7889
 7890    fn open_editor_at_anchor(
 7891        snapshot: &language::BufferSnapshot,
 7892        target: language::Anchor,
 7893        workspace: &Entity<Workspace>,
 7894        window: &mut Window,
 7895        cx: &mut App,
 7896    ) -> Task<Result<()>> {
 7897        workspace.update(cx, |workspace, cx| {
 7898            let path = snapshot.file().map(|file| file.full_path(cx));
 7899            let Some(path) =
 7900                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7901            else {
 7902                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7903            };
 7904            let target = text::ToPoint::to_point(&target, snapshot);
 7905            let item = workspace.open_path(path, None, true, window, cx);
 7906            window.spawn(cx, async move |cx| {
 7907                let Some(editor) = item.await?.downcast::<Editor>() else {
 7908                    return Ok(());
 7909                };
 7910                editor
 7911                    .update_in(cx, |editor, window, cx| {
 7912                        editor.go_to_singleton_buffer_point(target, window, cx);
 7913                    })
 7914                    .ok();
 7915                anyhow::Ok(())
 7916            })
 7917        })
 7918    }
 7919
 7920    pub fn has_active_edit_prediction(&self) -> bool {
 7921        self.active_edit_prediction.is_some()
 7922    }
 7923
 7924    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7925        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7926            return false;
 7927        };
 7928
 7929        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7930        self.clear_highlights::<EditPredictionHighlight>(cx);
 7931        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7932        true
 7933    }
 7934
 7935    /// Returns true when we're displaying the edit prediction popover below the cursor
 7936    /// like we are not previewing and the LSP autocomplete menu is visible
 7937    /// or we are in `when_holding_modifier` mode.
 7938    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7939        if self.edit_prediction_preview_is_active()
 7940            || !self.show_edit_predictions_in_menu()
 7941            || !self.edit_predictions_enabled()
 7942        {
 7943            return false;
 7944        }
 7945
 7946        if self.has_visible_completions_menu() {
 7947            return true;
 7948        }
 7949
 7950        has_completion && self.edit_prediction_requires_modifier()
 7951    }
 7952
 7953    fn handle_modifiers_changed(
 7954        &mut self,
 7955        modifiers: Modifiers,
 7956        position_map: &PositionMap,
 7957        window: &mut Window,
 7958        cx: &mut Context<Self>,
 7959    ) {
 7960        // Ensure that the edit prediction preview is updated, even when not
 7961        // enabled, if there's an active edit prediction preview.
 7962        if self.show_edit_predictions_in_menu()
 7963            || matches!(
 7964                self.edit_prediction_preview,
 7965                EditPredictionPreview::Active { .. }
 7966            )
 7967        {
 7968            self.update_edit_prediction_preview(&modifiers, window, cx);
 7969        }
 7970
 7971        self.update_selection_mode(&modifiers, position_map, window, cx);
 7972
 7973        let mouse_position = window.mouse_position();
 7974        if !position_map.text_hitbox.is_hovered(window) {
 7975            return;
 7976        }
 7977
 7978        self.update_hovered_link(
 7979            position_map.point_for_position(mouse_position),
 7980            &position_map.snapshot,
 7981            modifiers,
 7982            window,
 7983            cx,
 7984        )
 7985    }
 7986
 7987    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7988        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7989            MultiCursorModifier::Alt => modifiers.secondary(),
 7990            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7991        }
 7992    }
 7993
 7994    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7995        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7996            MultiCursorModifier::Alt => modifiers.alt,
 7997            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7998        }
 7999    }
 8000
 8001    fn columnar_selection_mode(
 8002        modifiers: &Modifiers,
 8003        cx: &mut Context<Self>,
 8004    ) -> Option<ColumnarMode> {
 8005        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8006            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8007                Some(ColumnarMode::FromMouse)
 8008            } else if Self::is_alt_pressed(modifiers, cx) {
 8009                Some(ColumnarMode::FromSelection)
 8010            } else {
 8011                None
 8012            }
 8013        } else {
 8014            None
 8015        }
 8016    }
 8017
 8018    fn update_selection_mode(
 8019        &mut self,
 8020        modifiers: &Modifiers,
 8021        position_map: &PositionMap,
 8022        window: &mut Window,
 8023        cx: &mut Context<Self>,
 8024    ) {
 8025        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8026            return;
 8027        };
 8028        if self.selections.pending_anchor().is_none() {
 8029            return;
 8030        }
 8031
 8032        let mouse_position = window.mouse_position();
 8033        let point_for_position = position_map.point_for_position(mouse_position);
 8034        let position = point_for_position.previous_valid;
 8035
 8036        self.select(
 8037            SelectPhase::BeginColumnar {
 8038                position,
 8039                reset: false,
 8040                mode,
 8041                goal_column: point_for_position.exact_unclipped.column(),
 8042            },
 8043            window,
 8044            cx,
 8045        );
 8046    }
 8047
 8048    fn update_edit_prediction_preview(
 8049        &mut self,
 8050        modifiers: &Modifiers,
 8051        window: &mut Window,
 8052        cx: &mut Context<Self>,
 8053    ) {
 8054        let mut modifiers_held = false;
 8055
 8056        // Check bindings for all granularities.
 8057        // If the user holds the key for Word, Line, or Full, we want to show the preview.
 8058        let granularities = [
 8059            EditPredictionGranularity::Full,
 8060            EditPredictionGranularity::Line,
 8061            EditPredictionGranularity::Word,
 8062        ];
 8063
 8064        for granularity in granularities {
 8065            if let Some(keystroke) = self
 8066                .accept_edit_prediction_keybind(granularity, window, cx)
 8067                .keystroke()
 8068            {
 8069                modifiers_held = modifiers_held
 8070                    || (keystroke.modifiers() == modifiers && keystroke.modifiers().modified());
 8071            }
 8072        }
 8073
 8074        if modifiers_held {
 8075            if matches!(
 8076                self.edit_prediction_preview,
 8077                EditPredictionPreview::Inactive { .. }
 8078            ) {
 8079                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 8080                    provider.provider.did_show(cx)
 8081                }
 8082
 8083                self.edit_prediction_preview = EditPredictionPreview::Active {
 8084                    previous_scroll_position: None,
 8085                    since: Instant::now(),
 8086                };
 8087
 8088                self.update_visible_edit_prediction(window, cx);
 8089                cx.notify();
 8090            }
 8091        } else if let EditPredictionPreview::Active {
 8092            previous_scroll_position,
 8093            since,
 8094        } = self.edit_prediction_preview
 8095        {
 8096            if let (Some(previous_scroll_position), Some(position_map)) =
 8097                (previous_scroll_position, self.last_position_map.as_ref())
 8098            {
 8099                self.set_scroll_position(
 8100                    previous_scroll_position
 8101                        .scroll_position(&position_map.snapshot.display_snapshot),
 8102                    window,
 8103                    cx,
 8104                );
 8105            }
 8106
 8107            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8108                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8109            };
 8110            self.clear_row_highlights::<EditPredictionPreview>();
 8111            self.update_visible_edit_prediction(window, cx);
 8112            cx.notify();
 8113        }
 8114    }
 8115
 8116    fn update_visible_edit_prediction(
 8117        &mut self,
 8118        _window: &mut Window,
 8119        cx: &mut Context<Self>,
 8120    ) -> Option<()> {
 8121        if DisableAiSettings::get_global(cx).disable_ai {
 8122            return None;
 8123        }
 8124
 8125        if self.ime_transaction.is_some() {
 8126            self.discard_edit_prediction(false, cx);
 8127            return None;
 8128        }
 8129
 8130        let selection = self.selections.newest_anchor();
 8131        let cursor = selection.head();
 8132        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8133        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8134        let excerpt_id = cursor.excerpt_id;
 8135
 8136        let show_in_menu = self.show_edit_predictions_in_menu();
 8137        let completions_menu_has_precedence = !show_in_menu
 8138            && (self.context_menu.borrow().is_some()
 8139                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8140
 8141        if completions_menu_has_precedence
 8142            || !offset_selection.is_empty()
 8143            || self
 8144                .active_edit_prediction
 8145                .as_ref()
 8146                .is_some_and(|completion| {
 8147                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8148                        return false;
 8149                    };
 8150                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8151                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8152                    !invalidation_range.contains(&offset_selection.head())
 8153                })
 8154        {
 8155            self.discard_edit_prediction(false, cx);
 8156            return None;
 8157        }
 8158
 8159        self.take_active_edit_prediction(cx);
 8160        let Some(provider) = self.edit_prediction_provider() else {
 8161            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8162            return None;
 8163        };
 8164
 8165        let (buffer, cursor_buffer_position) =
 8166            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8167
 8168        self.edit_prediction_settings =
 8169            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8170
 8171        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8172
 8173        if self.edit_prediction_indent_conflict {
 8174            let cursor_point = cursor.to_point(&multibuffer);
 8175            let mut suggested_indent = None;
 8176            multibuffer.suggested_indents_callback(
 8177                cursor_point.row..cursor_point.row + 1,
 8178                |_, indent| {
 8179                    suggested_indent = Some(indent);
 8180                    ControlFlow::Break(())
 8181                },
 8182                cx,
 8183            );
 8184
 8185            if let Some(indent) = suggested_indent
 8186                && indent.len == cursor_point.column
 8187            {
 8188                self.edit_prediction_indent_conflict = false;
 8189            }
 8190        }
 8191
 8192        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8193
 8194        let (completion_id, edits, edit_preview) = match edit_prediction {
 8195            edit_prediction_types::EditPrediction::Local {
 8196                id,
 8197                edits,
 8198                edit_preview,
 8199            } => (id, edits, edit_preview),
 8200            edit_prediction_types::EditPrediction::Jump {
 8201                id,
 8202                snapshot,
 8203                target,
 8204            } => {
 8205                self.stale_edit_prediction_in_menu = None;
 8206                self.active_edit_prediction = Some(EditPredictionState {
 8207                    inlay_ids: vec![],
 8208                    completion: EditPrediction::MoveOutside { snapshot, target },
 8209                    completion_id: id,
 8210                    invalidation_range: None,
 8211                });
 8212                cx.notify();
 8213                return Some(());
 8214            }
 8215        };
 8216
 8217        let edits = edits
 8218            .into_iter()
 8219            .flat_map(|(range, new_text)| {
 8220                Some((
 8221                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8222                    new_text,
 8223                ))
 8224            })
 8225            .collect::<Vec<_>>();
 8226        if edits.is_empty() {
 8227            return None;
 8228        }
 8229
 8230        let first_edit_start = edits.first().unwrap().0.start;
 8231        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8232        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8233
 8234        let last_edit_end = edits.last().unwrap().0.end;
 8235        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8236        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8237
 8238        let cursor_row = cursor.to_point(&multibuffer).row;
 8239
 8240        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8241
 8242        let mut inlay_ids = Vec::new();
 8243        let invalidation_row_range;
 8244        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8245            Some(cursor_row..edit_end_row)
 8246        } else if cursor_row > edit_end_row {
 8247            Some(edit_start_row..cursor_row)
 8248        } else {
 8249            None
 8250        };
 8251        let supports_jump = self
 8252            .edit_prediction_provider
 8253            .as_ref()
 8254            .map(|provider| provider.provider.supports_jump_to_edit())
 8255            .unwrap_or(true);
 8256
 8257        let is_move = supports_jump
 8258            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8259        let completion = if is_move {
 8260            invalidation_row_range =
 8261                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8262            let target = first_edit_start;
 8263            EditPrediction::MoveWithin { target, snapshot }
 8264        } else {
 8265            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8266                && !self.edit_predictions_hidden_for_vim_mode;
 8267
 8268            if show_completions_in_buffer {
 8269                if let Some(provider) = &self.edit_prediction_provider {
 8270                    provider.provider.did_show(cx);
 8271                }
 8272                if edits
 8273                    .iter()
 8274                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8275                {
 8276                    let mut inlays = Vec::new();
 8277                    for (range, new_text) in &edits {
 8278                        let inlay = Inlay::edit_prediction(
 8279                            post_inc(&mut self.next_inlay_id),
 8280                            range.start,
 8281                            new_text.as_ref(),
 8282                        );
 8283                        inlay_ids.push(inlay.id);
 8284                        inlays.push(inlay);
 8285                    }
 8286
 8287                    self.splice_inlays(&[], inlays, cx);
 8288                } else {
 8289                    let background_color = cx.theme().status().deleted_background;
 8290                    self.highlight_text::<EditPredictionHighlight>(
 8291                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8292                        HighlightStyle {
 8293                            background_color: Some(background_color),
 8294                            ..Default::default()
 8295                        },
 8296                        cx,
 8297                    );
 8298                }
 8299            }
 8300
 8301            invalidation_row_range = edit_start_row..edit_end_row;
 8302
 8303            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8304                if provider.show_tab_accept_marker() {
 8305                    EditDisplayMode::TabAccept
 8306                } else {
 8307                    EditDisplayMode::Inline
 8308                }
 8309            } else {
 8310                EditDisplayMode::DiffPopover
 8311            };
 8312
 8313            EditPrediction::Edit {
 8314                edits,
 8315                edit_preview,
 8316                display_mode,
 8317                snapshot,
 8318            }
 8319        };
 8320
 8321        let invalidation_range = multibuffer
 8322            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8323            ..multibuffer.anchor_after(Point::new(
 8324                invalidation_row_range.end,
 8325                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8326            ));
 8327
 8328        self.stale_edit_prediction_in_menu = None;
 8329        self.active_edit_prediction = Some(EditPredictionState {
 8330            inlay_ids,
 8331            completion,
 8332            completion_id,
 8333            invalidation_range: Some(invalidation_range),
 8334        });
 8335
 8336        cx.notify();
 8337
 8338        Some(())
 8339    }
 8340
 8341    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8342        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8343    }
 8344
 8345    fn clear_tasks(&mut self) {
 8346        self.tasks.clear()
 8347    }
 8348
 8349    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8350        if self.tasks.insert(key, value).is_some() {
 8351            // This case should hopefully be rare, but just in case...
 8352            log::error!(
 8353                "multiple different run targets found on a single line, only the last target will be rendered"
 8354            )
 8355        }
 8356    }
 8357
 8358    /// Get all display points of breakpoints that will be rendered within editor
 8359    ///
 8360    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8361    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8362    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8363    fn active_breakpoints(
 8364        &self,
 8365        range: Range<DisplayRow>,
 8366        window: &mut Window,
 8367        cx: &mut Context<Self>,
 8368    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8369        let mut breakpoint_display_points = HashMap::default();
 8370
 8371        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8372            return breakpoint_display_points;
 8373        };
 8374
 8375        let snapshot = self.snapshot(window, cx);
 8376
 8377        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8378        let Some(project) = self.project() else {
 8379            return breakpoint_display_points;
 8380        };
 8381
 8382        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8383            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8384
 8385        for (buffer_snapshot, range, excerpt_id) in
 8386            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8387        {
 8388            let Some(buffer) = project
 8389                .read(cx)
 8390                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8391            else {
 8392                continue;
 8393            };
 8394            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8395                &buffer,
 8396                Some(
 8397                    buffer_snapshot.anchor_before(range.start)
 8398                        ..buffer_snapshot.anchor_after(range.end),
 8399                ),
 8400                buffer_snapshot,
 8401                cx,
 8402            );
 8403            for (breakpoint, state) in breakpoints {
 8404                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8405                let position = multi_buffer_anchor
 8406                    .to_point(&multi_buffer_snapshot)
 8407                    .to_display_point(&snapshot);
 8408
 8409                breakpoint_display_points.insert(
 8410                    position.row(),
 8411                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8412                );
 8413            }
 8414        }
 8415
 8416        breakpoint_display_points
 8417    }
 8418
 8419    fn breakpoint_context_menu(
 8420        &self,
 8421        anchor: Anchor,
 8422        window: &mut Window,
 8423        cx: &mut Context<Self>,
 8424    ) -> Entity<ui::ContextMenu> {
 8425        let weak_editor = cx.weak_entity();
 8426        let focus_handle = self.focus_handle(cx);
 8427
 8428        let row = self
 8429            .buffer
 8430            .read(cx)
 8431            .snapshot(cx)
 8432            .summary_for_anchor::<Point>(&anchor)
 8433            .row;
 8434
 8435        let breakpoint = self
 8436            .breakpoint_at_row(row, window, cx)
 8437            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8438
 8439        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8440            "Edit Log Breakpoint"
 8441        } else {
 8442            "Set Log Breakpoint"
 8443        };
 8444
 8445        let condition_breakpoint_msg = if breakpoint
 8446            .as_ref()
 8447            .is_some_and(|bp| bp.1.condition.is_some())
 8448        {
 8449            "Edit Condition Breakpoint"
 8450        } else {
 8451            "Set Condition Breakpoint"
 8452        };
 8453
 8454        let hit_condition_breakpoint_msg = if breakpoint
 8455            .as_ref()
 8456            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8457        {
 8458            "Edit Hit Condition Breakpoint"
 8459        } else {
 8460            "Set Hit Condition Breakpoint"
 8461        };
 8462
 8463        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8464            "Unset Breakpoint"
 8465        } else {
 8466            "Set Breakpoint"
 8467        };
 8468
 8469        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8470
 8471        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8472            BreakpointState::Enabled => Some("Disable"),
 8473            BreakpointState::Disabled => Some("Enable"),
 8474        });
 8475
 8476        let (anchor, breakpoint) =
 8477            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8478
 8479        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8480            menu.on_blur_subscription(Subscription::new(|| {}))
 8481                .context(focus_handle)
 8482                .when(run_to_cursor, |this| {
 8483                    let weak_editor = weak_editor.clone();
 8484                    this.entry("Run to cursor", None, move |window, cx| {
 8485                        weak_editor
 8486                            .update(cx, |editor, cx| {
 8487                                editor.change_selections(
 8488                                    SelectionEffects::no_scroll(),
 8489                                    window,
 8490                                    cx,
 8491                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8492                                );
 8493                            })
 8494                            .ok();
 8495
 8496                        window.dispatch_action(Box::new(RunToCursor), cx);
 8497                    })
 8498                    .separator()
 8499                })
 8500                .when_some(toggle_state_msg, |this, msg| {
 8501                    this.entry(msg, None, {
 8502                        let weak_editor = weak_editor.clone();
 8503                        let breakpoint = breakpoint.clone();
 8504                        move |_window, cx| {
 8505                            weak_editor
 8506                                .update(cx, |this, cx| {
 8507                                    this.edit_breakpoint_at_anchor(
 8508                                        anchor,
 8509                                        breakpoint.as_ref().clone(),
 8510                                        BreakpointEditAction::InvertState,
 8511                                        cx,
 8512                                    );
 8513                                })
 8514                                .log_err();
 8515                        }
 8516                    })
 8517                })
 8518                .entry(set_breakpoint_msg, None, {
 8519                    let weak_editor = weak_editor.clone();
 8520                    let breakpoint = breakpoint.clone();
 8521                    move |_window, cx| {
 8522                        weak_editor
 8523                            .update(cx, |this, cx| {
 8524                                this.edit_breakpoint_at_anchor(
 8525                                    anchor,
 8526                                    breakpoint.as_ref().clone(),
 8527                                    BreakpointEditAction::Toggle,
 8528                                    cx,
 8529                                );
 8530                            })
 8531                            .log_err();
 8532                    }
 8533                })
 8534                .entry(log_breakpoint_msg, None, {
 8535                    let breakpoint = breakpoint.clone();
 8536                    let weak_editor = weak_editor.clone();
 8537                    move |window, cx| {
 8538                        weak_editor
 8539                            .update(cx, |this, cx| {
 8540                                this.add_edit_breakpoint_block(
 8541                                    anchor,
 8542                                    breakpoint.as_ref(),
 8543                                    BreakpointPromptEditAction::Log,
 8544                                    window,
 8545                                    cx,
 8546                                );
 8547                            })
 8548                            .log_err();
 8549                    }
 8550                })
 8551                .entry(condition_breakpoint_msg, None, {
 8552                    let breakpoint = breakpoint.clone();
 8553                    let weak_editor = weak_editor.clone();
 8554                    move |window, cx| {
 8555                        weak_editor
 8556                            .update(cx, |this, cx| {
 8557                                this.add_edit_breakpoint_block(
 8558                                    anchor,
 8559                                    breakpoint.as_ref(),
 8560                                    BreakpointPromptEditAction::Condition,
 8561                                    window,
 8562                                    cx,
 8563                                );
 8564                            })
 8565                            .log_err();
 8566                    }
 8567                })
 8568                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8569                    weak_editor
 8570                        .update(cx, |this, cx| {
 8571                            this.add_edit_breakpoint_block(
 8572                                anchor,
 8573                                breakpoint.as_ref(),
 8574                                BreakpointPromptEditAction::HitCondition,
 8575                                window,
 8576                                cx,
 8577                            );
 8578                        })
 8579                        .log_err();
 8580                })
 8581        })
 8582    }
 8583
 8584    fn render_breakpoint(
 8585        &self,
 8586        position: Anchor,
 8587        row: DisplayRow,
 8588        breakpoint: &Breakpoint,
 8589        state: Option<BreakpointSessionState>,
 8590        cx: &mut Context<Self>,
 8591    ) -> IconButton {
 8592        let is_rejected = state.is_some_and(|s| !s.verified);
 8593        // Is it a breakpoint that shows up when hovering over gutter?
 8594        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8595            (false, false),
 8596            |PhantomBreakpointIndicator {
 8597                 is_active,
 8598                 display_row,
 8599                 collides_with_existing_breakpoint,
 8600             }| {
 8601                (
 8602                    is_active && display_row == row,
 8603                    collides_with_existing_breakpoint,
 8604                )
 8605            },
 8606        );
 8607
 8608        let (color, icon) = {
 8609            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8610                (false, false) => ui::IconName::DebugBreakpoint,
 8611                (true, false) => ui::IconName::DebugLogBreakpoint,
 8612                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8613                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8614            };
 8615
 8616            let color = cx.theme().colors();
 8617
 8618            let color = if is_phantom {
 8619                if collides_with_existing {
 8620                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8621                } else {
 8622                    Color::Hint
 8623                }
 8624            } else if is_rejected {
 8625                Color::Disabled
 8626            } else {
 8627                Color::Debugger
 8628            };
 8629
 8630            (color, icon)
 8631        };
 8632
 8633        let breakpoint = Arc::from(breakpoint.clone());
 8634
 8635        let alt_as_text = gpui::Keystroke {
 8636            modifiers: Modifiers::secondary_key(),
 8637            ..Default::default()
 8638        };
 8639        let primary_action_text = if breakpoint.is_disabled() {
 8640            "Enable breakpoint"
 8641        } else if is_phantom && !collides_with_existing {
 8642            "Set breakpoint"
 8643        } else {
 8644            "Unset breakpoint"
 8645        };
 8646        let focus_handle = self.focus_handle.clone();
 8647
 8648        let meta = if is_rejected {
 8649            SharedString::from("No executable code is associated with this line.")
 8650        } else if collides_with_existing && !breakpoint.is_disabled() {
 8651            SharedString::from(format!(
 8652                "{alt_as_text}-click to disable,\nright-click for more options."
 8653            ))
 8654        } else {
 8655            SharedString::from("Right-click for more options.")
 8656        };
 8657        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8658            .icon_size(IconSize::XSmall)
 8659            .size(ui::ButtonSize::None)
 8660            .when(is_rejected, |this| {
 8661                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8662            })
 8663            .icon_color(color)
 8664            .style(ButtonStyle::Transparent)
 8665            .on_click(cx.listener({
 8666                move |editor, event: &ClickEvent, window, cx| {
 8667                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8668                        BreakpointEditAction::InvertState
 8669                    } else {
 8670                        BreakpointEditAction::Toggle
 8671                    };
 8672
 8673                    window.focus(&editor.focus_handle(cx), cx);
 8674                    editor.edit_breakpoint_at_anchor(
 8675                        position,
 8676                        breakpoint.as_ref().clone(),
 8677                        edit_action,
 8678                        cx,
 8679                    );
 8680                }
 8681            }))
 8682            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8683                editor.set_breakpoint_context_menu(
 8684                    row,
 8685                    Some(position),
 8686                    event.position(),
 8687                    window,
 8688                    cx,
 8689                );
 8690            }))
 8691            .tooltip(move |_window, cx| {
 8692                Tooltip::with_meta_in(
 8693                    primary_action_text,
 8694                    Some(&ToggleBreakpoint),
 8695                    meta.clone(),
 8696                    &focus_handle,
 8697                    cx,
 8698                )
 8699            })
 8700    }
 8701
 8702    fn build_tasks_context(
 8703        project: &Entity<Project>,
 8704        buffer: &Entity<Buffer>,
 8705        buffer_row: u32,
 8706        tasks: &Arc<RunnableTasks>,
 8707        cx: &mut Context<Self>,
 8708    ) -> Task<Option<task::TaskContext>> {
 8709        let position = Point::new(buffer_row, tasks.column);
 8710        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8711        let location = Location {
 8712            buffer: buffer.clone(),
 8713            range: range_start..range_start,
 8714        };
 8715        // Fill in the environmental variables from the tree-sitter captures
 8716        let mut captured_task_variables = TaskVariables::default();
 8717        for (capture_name, value) in tasks.extra_variables.clone() {
 8718            captured_task_variables.insert(
 8719                task::VariableName::Custom(capture_name.into()),
 8720                value.clone(),
 8721            );
 8722        }
 8723        project.update(cx, |project, cx| {
 8724            project.task_store().update(cx, |task_store, cx| {
 8725                task_store.task_context_for_location(captured_task_variables, location, cx)
 8726            })
 8727        })
 8728    }
 8729
 8730    pub fn spawn_nearest_task(
 8731        &mut self,
 8732        action: &SpawnNearestTask,
 8733        window: &mut Window,
 8734        cx: &mut Context<Self>,
 8735    ) {
 8736        let Some((workspace, _)) = self.workspace.clone() else {
 8737            return;
 8738        };
 8739        let Some(project) = self.project.clone() else {
 8740            return;
 8741        };
 8742
 8743        // Try to find a closest, enclosing node using tree-sitter that has a task
 8744        let Some((buffer, buffer_row, tasks)) = self
 8745            .find_enclosing_node_task(cx)
 8746            // Or find the task that's closest in row-distance.
 8747            .or_else(|| self.find_closest_task(cx))
 8748        else {
 8749            return;
 8750        };
 8751
 8752        let reveal_strategy = action.reveal;
 8753        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8754        cx.spawn_in(window, async move |_, cx| {
 8755            let context = task_context.await?;
 8756            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8757
 8758            let resolved = &mut resolved_task.resolved;
 8759            resolved.reveal = reveal_strategy;
 8760
 8761            workspace
 8762                .update_in(cx, |workspace, window, cx| {
 8763                    workspace.schedule_resolved_task(
 8764                        task_source_kind,
 8765                        resolved_task,
 8766                        false,
 8767                        window,
 8768                        cx,
 8769                    );
 8770                })
 8771                .ok()
 8772        })
 8773        .detach();
 8774    }
 8775
 8776    fn find_closest_task(
 8777        &mut self,
 8778        cx: &mut Context<Self>,
 8779    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8780        let cursor_row = self
 8781            .selections
 8782            .newest_adjusted(&self.display_snapshot(cx))
 8783            .head()
 8784            .row;
 8785
 8786        let ((buffer_id, row), tasks) = self
 8787            .tasks
 8788            .iter()
 8789            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8790
 8791        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8792        let tasks = Arc::new(tasks.to_owned());
 8793        Some((buffer, *row, tasks))
 8794    }
 8795
 8796    fn find_enclosing_node_task(
 8797        &mut self,
 8798        cx: &mut Context<Self>,
 8799    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8800        let snapshot = self.buffer.read(cx).snapshot(cx);
 8801        let offset = self
 8802            .selections
 8803            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8804            .head();
 8805        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8806        let offset = excerpt.map_offset_to_buffer(offset);
 8807        let buffer_id = excerpt.buffer().remote_id();
 8808
 8809        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8810        let mut cursor = layer.node().walk();
 8811
 8812        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8813            if cursor.node().end_byte() == offset.0 {
 8814                cursor.goto_next_sibling();
 8815            }
 8816        }
 8817
 8818        // Ascend to the smallest ancestor that contains the range and has a task.
 8819        loop {
 8820            let node = cursor.node();
 8821            let node_range = node.byte_range();
 8822            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8823
 8824            // Check if this node contains our offset
 8825            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8826                // If it contains offset, check for task
 8827                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8828                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8829                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8830                }
 8831            }
 8832
 8833            if !cursor.goto_parent() {
 8834                break;
 8835            }
 8836        }
 8837        None
 8838    }
 8839
 8840    fn render_run_indicator(
 8841        &self,
 8842        _style: &EditorStyle,
 8843        is_active: bool,
 8844        row: DisplayRow,
 8845        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8846        cx: &mut Context<Self>,
 8847    ) -> IconButton {
 8848        let color = Color::Muted;
 8849        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8850
 8851        IconButton::new(
 8852            ("run_indicator", row.0 as usize),
 8853            ui::IconName::PlayOutlined,
 8854        )
 8855        .shape(ui::IconButtonShape::Square)
 8856        .icon_size(IconSize::XSmall)
 8857        .icon_color(color)
 8858        .toggle_state(is_active)
 8859        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8860            let quick_launch = match e {
 8861                ClickEvent::Keyboard(_) => true,
 8862                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8863            };
 8864
 8865            window.focus(&editor.focus_handle(cx), cx);
 8866            editor.toggle_code_actions(
 8867                &ToggleCodeActions {
 8868                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8869                    quick_launch,
 8870                },
 8871                window,
 8872                cx,
 8873            );
 8874        }))
 8875        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8876            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8877        }))
 8878    }
 8879
 8880    pub fn context_menu_visible(&self) -> bool {
 8881        !self.edit_prediction_preview_is_active()
 8882            && self
 8883                .context_menu
 8884                .borrow()
 8885                .as_ref()
 8886                .is_some_and(|menu| menu.visible())
 8887    }
 8888
 8889    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8890        self.context_menu
 8891            .borrow()
 8892            .as_ref()
 8893            .map(|menu| menu.origin())
 8894    }
 8895
 8896    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8897        self.context_menu_options = Some(options);
 8898    }
 8899
 8900    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8901    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8902
 8903    fn render_edit_prediction_popover(
 8904        &mut self,
 8905        text_bounds: &Bounds<Pixels>,
 8906        content_origin: gpui::Point<Pixels>,
 8907        right_margin: Pixels,
 8908        editor_snapshot: &EditorSnapshot,
 8909        visible_row_range: Range<DisplayRow>,
 8910        scroll_top: ScrollOffset,
 8911        scroll_bottom: ScrollOffset,
 8912        line_layouts: &[LineWithInvisibles],
 8913        line_height: Pixels,
 8914        scroll_position: gpui::Point<ScrollOffset>,
 8915        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8916        newest_selection_head: Option<DisplayPoint>,
 8917        editor_width: Pixels,
 8918        style: &EditorStyle,
 8919        window: &mut Window,
 8920        cx: &mut App,
 8921    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8922        if self.mode().is_minimap() {
 8923            return None;
 8924        }
 8925        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8926
 8927        if self.edit_prediction_visible_in_cursor_popover(true) {
 8928            return None;
 8929        }
 8930
 8931        match &active_edit_prediction.completion {
 8932            EditPrediction::MoveWithin { target, .. } => {
 8933                let target_display_point = target.to_display_point(editor_snapshot);
 8934
 8935                if self.edit_prediction_requires_modifier() {
 8936                    if !self.edit_prediction_preview_is_active() {
 8937                        return None;
 8938                    }
 8939
 8940                    self.render_edit_prediction_modifier_jump_popover(
 8941                        text_bounds,
 8942                        content_origin,
 8943                        visible_row_range,
 8944                        line_layouts,
 8945                        line_height,
 8946                        scroll_pixel_position,
 8947                        newest_selection_head,
 8948                        target_display_point,
 8949                        window,
 8950                        cx,
 8951                    )
 8952                } else {
 8953                    self.render_edit_prediction_eager_jump_popover(
 8954                        text_bounds,
 8955                        content_origin,
 8956                        editor_snapshot,
 8957                        visible_row_range,
 8958                        scroll_top,
 8959                        scroll_bottom,
 8960                        line_height,
 8961                        scroll_pixel_position,
 8962                        target_display_point,
 8963                        editor_width,
 8964                        window,
 8965                        cx,
 8966                    )
 8967                }
 8968            }
 8969            EditPrediction::Edit {
 8970                display_mode: EditDisplayMode::Inline,
 8971                ..
 8972            } => None,
 8973            EditPrediction::Edit {
 8974                display_mode: EditDisplayMode::TabAccept,
 8975                edits,
 8976                ..
 8977            } => {
 8978                let range = &edits.first()?.0;
 8979                let target_display_point = range.end.to_display_point(editor_snapshot);
 8980
 8981                self.render_edit_prediction_end_of_line_popover(
 8982                    "Accept",
 8983                    editor_snapshot,
 8984                    visible_row_range,
 8985                    target_display_point,
 8986                    line_height,
 8987                    scroll_pixel_position,
 8988                    content_origin,
 8989                    editor_width,
 8990                    window,
 8991                    cx,
 8992                )
 8993            }
 8994            EditPrediction::Edit {
 8995                edits,
 8996                edit_preview,
 8997                display_mode: EditDisplayMode::DiffPopover,
 8998                snapshot,
 8999            } => self.render_edit_prediction_diff_popover(
 9000                text_bounds,
 9001                content_origin,
 9002                right_margin,
 9003                editor_snapshot,
 9004                visible_row_range,
 9005                line_layouts,
 9006                line_height,
 9007                scroll_position,
 9008                scroll_pixel_position,
 9009                newest_selection_head,
 9010                editor_width,
 9011                style,
 9012                edits,
 9013                edit_preview,
 9014                snapshot,
 9015                window,
 9016                cx,
 9017            ),
 9018            EditPrediction::MoveOutside { snapshot, .. } => {
 9019                let mut element = self
 9020                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9021                    .into_any();
 9022
 9023                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9024                let origin_x = text_bounds.size.width - size.width - px(30.);
 9025                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9026                element.prepaint_at(origin, window, cx);
 9027
 9028                Some((element, origin))
 9029            }
 9030        }
 9031    }
 9032
 9033    fn render_edit_prediction_modifier_jump_popover(
 9034        &mut self,
 9035        text_bounds: &Bounds<Pixels>,
 9036        content_origin: gpui::Point<Pixels>,
 9037        visible_row_range: Range<DisplayRow>,
 9038        line_layouts: &[LineWithInvisibles],
 9039        line_height: Pixels,
 9040        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9041        newest_selection_head: Option<DisplayPoint>,
 9042        target_display_point: DisplayPoint,
 9043        window: &mut Window,
 9044        cx: &mut App,
 9045    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9046        let scrolled_content_origin =
 9047            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9048
 9049        const SCROLL_PADDING_Y: Pixels = px(12.);
 9050
 9051        if target_display_point.row() < visible_row_range.start {
 9052            return self.render_edit_prediction_scroll_popover(
 9053                |_| SCROLL_PADDING_Y,
 9054                IconName::ArrowUp,
 9055                visible_row_range,
 9056                line_layouts,
 9057                newest_selection_head,
 9058                scrolled_content_origin,
 9059                window,
 9060                cx,
 9061            );
 9062        } else if target_display_point.row() >= visible_row_range.end {
 9063            return self.render_edit_prediction_scroll_popover(
 9064                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9065                IconName::ArrowDown,
 9066                visible_row_range,
 9067                line_layouts,
 9068                newest_selection_head,
 9069                scrolled_content_origin,
 9070                window,
 9071                cx,
 9072            );
 9073        }
 9074
 9075        const POLE_WIDTH: Pixels = px(2.);
 9076
 9077        let line_layout =
 9078            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9079        let target_column = target_display_point.column() as usize;
 9080
 9081        let target_x = line_layout.x_for_index(target_column);
 9082        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9083            - scroll_pixel_position.y;
 9084
 9085        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9086
 9087        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9088        border_color.l += 0.001;
 9089
 9090        let mut element = v_flex()
 9091            .items_end()
 9092            .when(flag_on_right, |el| el.items_start())
 9093            .child(if flag_on_right {
 9094                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9095                    .rounded_bl(px(0.))
 9096                    .rounded_tl(px(0.))
 9097                    .border_l_2()
 9098                    .border_color(border_color)
 9099            } else {
 9100                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9101                    .rounded_br(px(0.))
 9102                    .rounded_tr(px(0.))
 9103                    .border_r_2()
 9104                    .border_color(border_color)
 9105            })
 9106            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9107            .into_any();
 9108
 9109        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9110
 9111        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9112            - point(
 9113                if flag_on_right {
 9114                    POLE_WIDTH
 9115                } else {
 9116                    size.width - POLE_WIDTH
 9117                },
 9118                size.height - line_height,
 9119            );
 9120
 9121        origin.x = origin.x.max(content_origin.x);
 9122
 9123        element.prepaint_at(origin, window, cx);
 9124
 9125        Some((element, origin))
 9126    }
 9127
 9128    fn render_edit_prediction_scroll_popover(
 9129        &mut self,
 9130        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9131        scroll_icon: IconName,
 9132        visible_row_range: Range<DisplayRow>,
 9133        line_layouts: &[LineWithInvisibles],
 9134        newest_selection_head: Option<DisplayPoint>,
 9135        scrolled_content_origin: gpui::Point<Pixels>,
 9136        window: &mut Window,
 9137        cx: &mut App,
 9138    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9139        let mut element = self
 9140            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9141            .into_any();
 9142
 9143        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9144
 9145        let cursor = newest_selection_head?;
 9146        let cursor_row_layout =
 9147            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9148        let cursor_column = cursor.column() as usize;
 9149
 9150        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9151
 9152        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9153
 9154        element.prepaint_at(origin, window, cx);
 9155        Some((element, origin))
 9156    }
 9157
 9158    fn render_edit_prediction_eager_jump_popover(
 9159        &mut self,
 9160        text_bounds: &Bounds<Pixels>,
 9161        content_origin: gpui::Point<Pixels>,
 9162        editor_snapshot: &EditorSnapshot,
 9163        visible_row_range: Range<DisplayRow>,
 9164        scroll_top: ScrollOffset,
 9165        scroll_bottom: ScrollOffset,
 9166        line_height: Pixels,
 9167        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9168        target_display_point: DisplayPoint,
 9169        editor_width: Pixels,
 9170        window: &mut Window,
 9171        cx: &mut App,
 9172    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9173        if target_display_point.row().as_f64() < scroll_top {
 9174            let mut element = self
 9175                .render_edit_prediction_line_popover(
 9176                    "Jump to Edit",
 9177                    Some(IconName::ArrowUp),
 9178                    window,
 9179                    cx,
 9180                )
 9181                .into_any();
 9182
 9183            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9184            let offset = point(
 9185                (text_bounds.size.width - size.width) / 2.,
 9186                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9187            );
 9188
 9189            let origin = text_bounds.origin + offset;
 9190            element.prepaint_at(origin, window, cx);
 9191            Some((element, origin))
 9192        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9193            let mut element = self
 9194                .render_edit_prediction_line_popover(
 9195                    "Jump to Edit",
 9196                    Some(IconName::ArrowDown),
 9197                    window,
 9198                    cx,
 9199                )
 9200                .into_any();
 9201
 9202            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9203            let offset = point(
 9204                (text_bounds.size.width - size.width) / 2.,
 9205                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9206            );
 9207
 9208            let origin = text_bounds.origin + offset;
 9209            element.prepaint_at(origin, window, cx);
 9210            Some((element, origin))
 9211        } else {
 9212            self.render_edit_prediction_end_of_line_popover(
 9213                "Jump to Edit",
 9214                editor_snapshot,
 9215                visible_row_range,
 9216                target_display_point,
 9217                line_height,
 9218                scroll_pixel_position,
 9219                content_origin,
 9220                editor_width,
 9221                window,
 9222                cx,
 9223            )
 9224        }
 9225    }
 9226
 9227    fn render_edit_prediction_end_of_line_popover(
 9228        self: &mut Editor,
 9229        label: &'static str,
 9230        editor_snapshot: &EditorSnapshot,
 9231        visible_row_range: Range<DisplayRow>,
 9232        target_display_point: DisplayPoint,
 9233        line_height: Pixels,
 9234        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9235        content_origin: gpui::Point<Pixels>,
 9236        editor_width: Pixels,
 9237        window: &mut Window,
 9238        cx: &mut App,
 9239    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9240        let target_line_end = DisplayPoint::new(
 9241            target_display_point.row(),
 9242            editor_snapshot.line_len(target_display_point.row()),
 9243        );
 9244
 9245        let mut element = self
 9246            .render_edit_prediction_line_popover(label, None, window, cx)
 9247            .into_any();
 9248
 9249        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9250
 9251        let line_origin =
 9252            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9253
 9254        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9255        let mut origin = start_point
 9256            + line_origin
 9257            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9258        origin.x = origin.x.max(content_origin.x);
 9259
 9260        let max_x = content_origin.x + editor_width - size.width;
 9261
 9262        if origin.x > max_x {
 9263            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9264
 9265            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9266                origin.y += offset;
 9267                IconName::ArrowUp
 9268            } else {
 9269                origin.y -= offset;
 9270                IconName::ArrowDown
 9271            };
 9272
 9273            element = self
 9274                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9275                .into_any();
 9276
 9277            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9278
 9279            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9280        }
 9281
 9282        element.prepaint_at(origin, window, cx);
 9283        Some((element, origin))
 9284    }
 9285
 9286    fn render_edit_prediction_diff_popover(
 9287        self: &Editor,
 9288        text_bounds: &Bounds<Pixels>,
 9289        content_origin: gpui::Point<Pixels>,
 9290        right_margin: Pixels,
 9291        editor_snapshot: &EditorSnapshot,
 9292        visible_row_range: Range<DisplayRow>,
 9293        line_layouts: &[LineWithInvisibles],
 9294        line_height: Pixels,
 9295        scroll_position: gpui::Point<ScrollOffset>,
 9296        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9297        newest_selection_head: Option<DisplayPoint>,
 9298        editor_width: Pixels,
 9299        style: &EditorStyle,
 9300        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9301        edit_preview: &Option<language::EditPreview>,
 9302        snapshot: &language::BufferSnapshot,
 9303        window: &mut Window,
 9304        cx: &mut App,
 9305    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9306        let edit_start = edits
 9307            .first()
 9308            .unwrap()
 9309            .0
 9310            .start
 9311            .to_display_point(editor_snapshot);
 9312        let edit_end = edits
 9313            .last()
 9314            .unwrap()
 9315            .0
 9316            .end
 9317            .to_display_point(editor_snapshot);
 9318
 9319        let is_visible = visible_row_range.contains(&edit_start.row())
 9320            || visible_row_range.contains(&edit_end.row());
 9321        if !is_visible {
 9322            return None;
 9323        }
 9324
 9325        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9326            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9327        } else {
 9328            // Fallback for providers without edit_preview
 9329            crate::edit_prediction_fallback_text(edits, cx)
 9330        };
 9331
 9332        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9333        let line_count = highlighted_edits.text.lines().count();
 9334
 9335        const BORDER_WIDTH: Pixels = px(1.);
 9336
 9337        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9338        let has_keybind = keybind.is_some();
 9339
 9340        let mut element = h_flex()
 9341            .items_start()
 9342            .child(
 9343                h_flex()
 9344                    .bg(cx.theme().colors().editor_background)
 9345                    .border(BORDER_WIDTH)
 9346                    .shadow_xs()
 9347                    .border_color(cx.theme().colors().border)
 9348                    .rounded_l_lg()
 9349                    .when(line_count > 1, |el| el.rounded_br_lg())
 9350                    .pr_1()
 9351                    .child(styled_text),
 9352            )
 9353            .child(
 9354                h_flex()
 9355                    .h(line_height + BORDER_WIDTH * 2.)
 9356                    .px_1p5()
 9357                    .gap_1()
 9358                    // Workaround: For some reason, there's a gap if we don't do this
 9359                    .ml(-BORDER_WIDTH)
 9360                    .shadow(vec![gpui::BoxShadow {
 9361                        color: gpui::black().opacity(0.05),
 9362                        offset: point(px(1.), px(1.)),
 9363                        blur_radius: px(2.),
 9364                        spread_radius: px(0.),
 9365                    }])
 9366                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9367                    .border(BORDER_WIDTH)
 9368                    .border_color(cx.theme().colors().border)
 9369                    .rounded_r_lg()
 9370                    .id("edit_prediction_diff_popover_keybind")
 9371                    .when(!has_keybind, |el| {
 9372                        let status_colors = cx.theme().status();
 9373
 9374                        el.bg(status_colors.error_background)
 9375                            .border_color(status_colors.error.opacity(0.6))
 9376                            .child(Icon::new(IconName::Info).color(Color::Error))
 9377                            .cursor_default()
 9378                            .hoverable_tooltip(move |_window, cx| {
 9379                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9380                            })
 9381                    })
 9382                    .children(keybind),
 9383            )
 9384            .into_any();
 9385
 9386        let longest_row =
 9387            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9388        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9389            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9390        } else {
 9391            layout_line(
 9392                longest_row,
 9393                editor_snapshot,
 9394                style,
 9395                editor_width,
 9396                |_| false,
 9397                window,
 9398                cx,
 9399            )
 9400            .width
 9401        };
 9402
 9403        let viewport_bounds =
 9404            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9405                right: -right_margin,
 9406                ..Default::default()
 9407            });
 9408
 9409        let x_after_longest = Pixels::from(
 9410            ScrollPixelOffset::from(
 9411                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9412            ) - scroll_pixel_position.x,
 9413        );
 9414
 9415        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9416
 9417        // Fully visible if it can be displayed within the window (allow overlapping other
 9418        // panes). However, this is only allowed if the popover starts within text_bounds.
 9419        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9420            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9421
 9422        let mut origin = if can_position_to_the_right {
 9423            point(
 9424                x_after_longest,
 9425                text_bounds.origin.y
 9426                    + Pixels::from(
 9427                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9428                            - scroll_pixel_position.y,
 9429                    ),
 9430            )
 9431        } else {
 9432            let cursor_row = newest_selection_head.map(|head| head.row());
 9433            let above_edit = edit_start
 9434                .row()
 9435                .0
 9436                .checked_sub(line_count as u32)
 9437                .map(DisplayRow);
 9438            let below_edit = Some(edit_end.row() + 1);
 9439            let above_cursor =
 9440                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9441            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9442
 9443            // Place the edit popover adjacent to the edit if there is a location
 9444            // available that is onscreen and does not obscure the cursor. Otherwise,
 9445            // place it adjacent to the cursor.
 9446            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9447                .into_iter()
 9448                .flatten()
 9449                .find(|&start_row| {
 9450                    let end_row = start_row + line_count as u32;
 9451                    visible_row_range.contains(&start_row)
 9452                        && visible_row_range.contains(&end_row)
 9453                        && cursor_row
 9454                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9455                })?;
 9456
 9457            content_origin
 9458                + point(
 9459                    Pixels::from(-scroll_pixel_position.x),
 9460                    Pixels::from(
 9461                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9462                    ),
 9463                )
 9464        };
 9465
 9466        origin.x -= BORDER_WIDTH;
 9467
 9468        window.defer_draw(element, origin, 1);
 9469
 9470        // Do not return an element, since it will already be drawn due to defer_draw.
 9471        None
 9472    }
 9473
 9474    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9475        px(30.)
 9476    }
 9477
 9478    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9479        if self.read_only(cx) {
 9480            cx.theme().players().read_only()
 9481        } else {
 9482            self.style.as_ref().unwrap().local_player
 9483        }
 9484    }
 9485
 9486    fn render_edit_prediction_accept_keybind(
 9487        &self,
 9488        window: &mut Window,
 9489        cx: &mut App,
 9490    ) -> Option<AnyElement> {
 9491        let accept_binding =
 9492            self.accept_edit_prediction_keybind(EditPredictionGranularity::Full, window, cx);
 9493        let accept_keystroke = accept_binding.keystroke()?;
 9494
 9495        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9496
 9497        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9498            Color::Accent
 9499        } else {
 9500            Color::Muted
 9501        };
 9502
 9503        h_flex()
 9504            .px_0p5()
 9505            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9506            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9507            .text_size(TextSize::XSmall.rems(cx))
 9508            .child(h_flex().children(ui::render_modifiers(
 9509                accept_keystroke.modifiers(),
 9510                PlatformStyle::platform(),
 9511                Some(modifiers_color),
 9512                Some(IconSize::XSmall.rems().into()),
 9513                true,
 9514            )))
 9515            .when(is_platform_style_mac, |parent| {
 9516                parent.child(accept_keystroke.key().to_string())
 9517            })
 9518            .when(!is_platform_style_mac, |parent| {
 9519                parent.child(
 9520                    Key::new(
 9521                        util::capitalize(accept_keystroke.key()),
 9522                        Some(Color::Default),
 9523                    )
 9524                    .size(Some(IconSize::XSmall.rems().into())),
 9525                )
 9526            })
 9527            .into_any()
 9528            .into()
 9529    }
 9530
 9531    fn render_edit_prediction_line_popover(
 9532        &self,
 9533        label: impl Into<SharedString>,
 9534        icon: Option<IconName>,
 9535        window: &mut Window,
 9536        cx: &mut App,
 9537    ) -> Stateful<Div> {
 9538        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9539
 9540        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9541        let has_keybind = keybind.is_some();
 9542
 9543        h_flex()
 9544            .id("ep-line-popover")
 9545            .py_0p5()
 9546            .pl_1()
 9547            .pr(padding_right)
 9548            .gap_1()
 9549            .rounded_md()
 9550            .border_1()
 9551            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9552            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9553            .shadow_xs()
 9554            .when(!has_keybind, |el| {
 9555                let status_colors = cx.theme().status();
 9556
 9557                el.bg(status_colors.error_background)
 9558                    .border_color(status_colors.error.opacity(0.6))
 9559                    .pl_2()
 9560                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9561                    .cursor_default()
 9562                    .hoverable_tooltip(move |_window, cx| {
 9563                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9564                    })
 9565            })
 9566            .children(keybind)
 9567            .child(
 9568                Label::new(label)
 9569                    .size(LabelSize::Small)
 9570                    .when(!has_keybind, |el| {
 9571                        el.color(cx.theme().status().error.into()).strikethrough()
 9572                    }),
 9573            )
 9574            .when(!has_keybind, |el| {
 9575                el.child(
 9576                    h_flex().ml_1().child(
 9577                        Icon::new(IconName::Info)
 9578                            .size(IconSize::Small)
 9579                            .color(cx.theme().status().error.into()),
 9580                    ),
 9581                )
 9582            })
 9583            .when_some(icon, |element, icon| {
 9584                element.child(
 9585                    div()
 9586                        .mt(px(1.5))
 9587                        .child(Icon::new(icon).size(IconSize::Small)),
 9588                )
 9589            })
 9590    }
 9591
 9592    fn render_edit_prediction_jump_outside_popover(
 9593        &self,
 9594        snapshot: &BufferSnapshot,
 9595        window: &mut Window,
 9596        cx: &mut App,
 9597    ) -> Stateful<Div> {
 9598        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9599        let has_keybind = keybind.is_some();
 9600
 9601        let file_name = snapshot
 9602            .file()
 9603            .map(|file| SharedString::new(file.file_name(cx)))
 9604            .unwrap_or(SharedString::new_static("untitled"));
 9605
 9606        h_flex()
 9607            .id("ep-jump-outside-popover")
 9608            .py_1()
 9609            .px_2()
 9610            .gap_1()
 9611            .rounded_md()
 9612            .border_1()
 9613            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9614            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9615            .shadow_xs()
 9616            .when(!has_keybind, |el| {
 9617                let status_colors = cx.theme().status();
 9618
 9619                el.bg(status_colors.error_background)
 9620                    .border_color(status_colors.error.opacity(0.6))
 9621                    .pl_2()
 9622                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9623                    .cursor_default()
 9624                    .hoverable_tooltip(move |_window, cx| {
 9625                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9626                    })
 9627            })
 9628            .children(keybind)
 9629            .child(
 9630                Label::new(file_name)
 9631                    .size(LabelSize::Small)
 9632                    .buffer_font(cx)
 9633                    .when(!has_keybind, |el| {
 9634                        el.color(cx.theme().status().error.into()).strikethrough()
 9635                    }),
 9636            )
 9637            .when(!has_keybind, |el| {
 9638                el.child(
 9639                    h_flex().ml_1().child(
 9640                        Icon::new(IconName::Info)
 9641                            .size(IconSize::Small)
 9642                            .color(cx.theme().status().error.into()),
 9643                    ),
 9644                )
 9645            })
 9646            .child(
 9647                div()
 9648                    .mt(px(1.5))
 9649                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9650            )
 9651    }
 9652
 9653    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9654        let accent_color = cx.theme().colors().text_accent;
 9655        let editor_bg_color = cx.theme().colors().editor_background;
 9656        editor_bg_color.blend(accent_color.opacity(0.1))
 9657    }
 9658
 9659    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9660        let accent_color = cx.theme().colors().text_accent;
 9661        let editor_bg_color = cx.theme().colors().editor_background;
 9662        editor_bg_color.blend(accent_color.opacity(0.6))
 9663    }
 9664    fn get_prediction_provider_icon_name(
 9665        provider: &Option<RegisteredEditPredictionDelegate>,
 9666    ) -> IconName {
 9667        match provider {
 9668            Some(provider) => match provider.provider.name() {
 9669                "copilot" => IconName::Copilot,
 9670                "supermaven" => IconName::Supermaven,
 9671                _ => IconName::ZedPredict,
 9672            },
 9673            None => IconName::ZedPredict,
 9674        }
 9675    }
 9676
 9677    fn render_edit_prediction_cursor_popover(
 9678        &self,
 9679        min_width: Pixels,
 9680        max_width: Pixels,
 9681        cursor_point: Point,
 9682        style: &EditorStyle,
 9683        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9684        _window: &Window,
 9685        cx: &mut Context<Editor>,
 9686    ) -> Option<AnyElement> {
 9687        let provider = self.edit_prediction_provider.as_ref()?;
 9688        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9689
 9690        let is_refreshing = provider.provider.is_refreshing(cx);
 9691
 9692        fn pending_completion_container(icon: IconName) -> Div {
 9693            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9694        }
 9695
 9696        let completion = match &self.active_edit_prediction {
 9697            Some(prediction) => {
 9698                if !self.has_visible_completions_menu() {
 9699                    const RADIUS: Pixels = px(6.);
 9700                    const BORDER_WIDTH: Pixels = px(1.);
 9701
 9702                    return Some(
 9703                        h_flex()
 9704                            .elevation_2(cx)
 9705                            .border(BORDER_WIDTH)
 9706                            .border_color(cx.theme().colors().border)
 9707                            .when(accept_keystroke.is_none(), |el| {
 9708                                el.border_color(cx.theme().status().error)
 9709                            })
 9710                            .rounded(RADIUS)
 9711                            .rounded_tl(px(0.))
 9712                            .overflow_hidden()
 9713                            .child(div().px_1p5().child(match &prediction.completion {
 9714                                EditPrediction::MoveWithin { target, snapshot } => {
 9715                                    use text::ToPoint as _;
 9716                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9717                                    {
 9718                                        Icon::new(IconName::ZedPredictDown)
 9719                                    } else {
 9720                                        Icon::new(IconName::ZedPredictUp)
 9721                                    }
 9722                                }
 9723                                EditPrediction::MoveOutside { .. } => {
 9724                                    // TODO [zeta2] custom icon for external jump?
 9725                                    Icon::new(provider_icon)
 9726                                }
 9727                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9728                            }))
 9729                            .child(
 9730                                h_flex()
 9731                                    .gap_1()
 9732                                    .py_1()
 9733                                    .px_2()
 9734                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9735                                    .border_l_1()
 9736                                    .border_color(cx.theme().colors().border)
 9737                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9738                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9739                                        el.child(
 9740                                            Label::new("Hold")
 9741                                                .size(LabelSize::Small)
 9742                                                .when(accept_keystroke.is_none(), |el| {
 9743                                                    el.strikethrough()
 9744                                                })
 9745                                                .line_height_style(LineHeightStyle::UiLabel),
 9746                                        )
 9747                                    })
 9748                                    .id("edit_prediction_cursor_popover_keybind")
 9749                                    .when(accept_keystroke.is_none(), |el| {
 9750                                        let status_colors = cx.theme().status();
 9751
 9752                                        el.bg(status_colors.error_background)
 9753                                            .border_color(status_colors.error.opacity(0.6))
 9754                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9755                                            .cursor_default()
 9756                                            .hoverable_tooltip(move |_window, cx| {
 9757                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9758                                                    .into()
 9759                                            })
 9760                                    })
 9761                                    .when_some(
 9762                                        accept_keystroke.as_ref(),
 9763                                        |el, accept_keystroke| {
 9764                                            el.child(h_flex().children(ui::render_modifiers(
 9765                                                accept_keystroke.modifiers(),
 9766                                                PlatformStyle::platform(),
 9767                                                Some(Color::Default),
 9768                                                Some(IconSize::XSmall.rems().into()),
 9769                                                false,
 9770                                            )))
 9771                                        },
 9772                                    ),
 9773                            )
 9774                            .into_any(),
 9775                    );
 9776                }
 9777
 9778                self.render_edit_prediction_cursor_popover_preview(
 9779                    prediction,
 9780                    cursor_point,
 9781                    style,
 9782                    cx,
 9783                )?
 9784            }
 9785
 9786            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9787                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9788                    stale_completion,
 9789                    cursor_point,
 9790                    style,
 9791                    cx,
 9792                )?,
 9793
 9794                None => pending_completion_container(provider_icon)
 9795                    .child(Label::new("...").size(LabelSize::Small)),
 9796            },
 9797
 9798            None => pending_completion_container(provider_icon)
 9799                .child(Label::new("...").size(LabelSize::Small)),
 9800        };
 9801
 9802        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9803            completion
 9804                .with_animation(
 9805                    "loading-completion",
 9806                    Animation::new(Duration::from_secs(2))
 9807                        .repeat()
 9808                        .with_easing(pulsating_between(0.4, 0.8)),
 9809                    |label, delta| label.opacity(delta),
 9810                )
 9811                .into_any_element()
 9812        } else {
 9813            completion.into_any_element()
 9814        };
 9815
 9816        let has_completion = self.active_edit_prediction.is_some();
 9817
 9818        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9819        Some(
 9820            h_flex()
 9821                .min_w(min_width)
 9822                .max_w(max_width)
 9823                .flex_1()
 9824                .elevation_2(cx)
 9825                .border_color(cx.theme().colors().border)
 9826                .child(
 9827                    div()
 9828                        .flex_1()
 9829                        .py_1()
 9830                        .px_2()
 9831                        .overflow_hidden()
 9832                        .child(completion),
 9833                )
 9834                .when_some(accept_keystroke, |el, accept_keystroke| {
 9835                    if !accept_keystroke.modifiers().modified() {
 9836                        return el;
 9837                    }
 9838
 9839                    el.child(
 9840                        h_flex()
 9841                            .h_full()
 9842                            .border_l_1()
 9843                            .rounded_r_lg()
 9844                            .border_color(cx.theme().colors().border)
 9845                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9846                            .gap_1()
 9847                            .py_1()
 9848                            .px_2()
 9849                            .child(
 9850                                h_flex()
 9851                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9852                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9853                                    .child(h_flex().children(ui::render_modifiers(
 9854                                        accept_keystroke.modifiers(),
 9855                                        PlatformStyle::platform(),
 9856                                        Some(if !has_completion {
 9857                                            Color::Muted
 9858                                        } else {
 9859                                            Color::Default
 9860                                        }),
 9861                                        None,
 9862                                        false,
 9863                                    ))),
 9864                            )
 9865                            .child(Label::new("Preview").into_any_element())
 9866                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9867                    )
 9868                })
 9869                .into_any(),
 9870        )
 9871    }
 9872
 9873    fn render_edit_prediction_cursor_popover_preview(
 9874        &self,
 9875        completion: &EditPredictionState,
 9876        cursor_point: Point,
 9877        style: &EditorStyle,
 9878        cx: &mut Context<Editor>,
 9879    ) -> Option<Div> {
 9880        use text::ToPoint as _;
 9881
 9882        fn render_relative_row_jump(
 9883            prefix: impl Into<String>,
 9884            current_row: u32,
 9885            target_row: u32,
 9886        ) -> Div {
 9887            let (row_diff, arrow) = if target_row < current_row {
 9888                (current_row - target_row, IconName::ArrowUp)
 9889            } else {
 9890                (target_row - current_row, IconName::ArrowDown)
 9891            };
 9892
 9893            h_flex()
 9894                .child(
 9895                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9896                        .color(Color::Muted)
 9897                        .size(LabelSize::Small),
 9898                )
 9899                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9900        }
 9901
 9902        let supports_jump = self
 9903            .edit_prediction_provider
 9904            .as_ref()
 9905            .map(|provider| provider.provider.supports_jump_to_edit())
 9906            .unwrap_or(true);
 9907
 9908        match &completion.completion {
 9909            EditPrediction::MoveWithin {
 9910                target, snapshot, ..
 9911            } => {
 9912                if !supports_jump {
 9913                    return None;
 9914                }
 9915
 9916                Some(
 9917                    h_flex()
 9918                        .px_2()
 9919                        .gap_2()
 9920                        .flex_1()
 9921                        .child(
 9922                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9923                                Icon::new(IconName::ZedPredictDown)
 9924                            } else {
 9925                                Icon::new(IconName::ZedPredictUp)
 9926                            },
 9927                        )
 9928                        .child(Label::new("Jump to Edit")),
 9929                )
 9930            }
 9931            EditPrediction::MoveOutside { snapshot, .. } => {
 9932                let file_name = snapshot
 9933                    .file()
 9934                    .map(|file| file.file_name(cx))
 9935                    .unwrap_or("untitled");
 9936                Some(
 9937                    h_flex()
 9938                        .px_2()
 9939                        .gap_2()
 9940                        .flex_1()
 9941                        .child(Icon::new(IconName::ZedPredict))
 9942                        .child(Label::new(format!("Jump to {file_name}"))),
 9943                )
 9944            }
 9945            EditPrediction::Edit {
 9946                edits,
 9947                edit_preview,
 9948                snapshot,
 9949                display_mode: _,
 9950            } => {
 9951                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9952
 9953                let (highlighted_edits, has_more_lines) =
 9954                    if let Some(edit_preview) = edit_preview.as_ref() {
 9955                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9956                            .first_line_preview()
 9957                    } else {
 9958                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9959                    };
 9960
 9961                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9962                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9963
 9964                let preview = h_flex()
 9965                    .gap_1()
 9966                    .min_w_16()
 9967                    .child(styled_text)
 9968                    .when(has_more_lines, |parent| parent.child(""));
 9969
 9970                let left = if supports_jump && first_edit_row != cursor_point.row {
 9971                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9972                        .into_any_element()
 9973                } else {
 9974                    let icon_name =
 9975                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9976                    Icon::new(icon_name).into_any_element()
 9977                };
 9978
 9979                Some(
 9980                    h_flex()
 9981                        .h_full()
 9982                        .flex_1()
 9983                        .gap_2()
 9984                        .pr_1()
 9985                        .overflow_x_hidden()
 9986                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9987                        .child(left)
 9988                        .child(preview),
 9989                )
 9990            }
 9991        }
 9992    }
 9993
 9994    pub fn render_context_menu(
 9995        &mut self,
 9996        max_height_in_lines: u32,
 9997        window: &mut Window,
 9998        cx: &mut Context<Editor>,
 9999    ) -> Option<AnyElement> {
10000        let menu = self.context_menu.borrow();
10001        let menu = menu.as_ref()?;
10002        if !menu.visible() {
10003            return None;
10004        };
10005        self.style
10006            .as_ref()
10007            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10008    }
10009
10010    fn render_context_menu_aside(
10011        &mut self,
10012        max_size: Size<Pixels>,
10013        window: &mut Window,
10014        cx: &mut Context<Editor>,
10015    ) -> Option<AnyElement> {
10016        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10017            if menu.visible() {
10018                menu.render_aside(max_size, window, cx)
10019            } else {
10020                None
10021            }
10022        })
10023    }
10024
10025    fn hide_context_menu(
10026        &mut self,
10027        window: &mut Window,
10028        cx: &mut Context<Self>,
10029    ) -> Option<CodeContextMenu> {
10030        cx.notify();
10031        self.completion_tasks.clear();
10032        let context_menu = self.context_menu.borrow_mut().take();
10033        self.stale_edit_prediction_in_menu.take();
10034        self.update_visible_edit_prediction(window, cx);
10035        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10036            && let Some(completion_provider) = &self.completion_provider
10037        {
10038            completion_provider.selection_changed(None, window, cx);
10039        }
10040        context_menu
10041    }
10042
10043    fn show_snippet_choices(
10044        &mut self,
10045        choices: &Vec<String>,
10046        selection: Range<Anchor>,
10047        cx: &mut Context<Self>,
10048    ) {
10049        let Some((_, buffer, _)) = self
10050            .buffer()
10051            .read(cx)
10052            .excerpt_containing(selection.start, cx)
10053        else {
10054            return;
10055        };
10056        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10057        else {
10058            return;
10059        };
10060        if buffer != end_buffer {
10061            log::error!("expected anchor range to have matching buffer IDs");
10062            return;
10063        }
10064
10065        let id = post_inc(&mut self.next_completion_id);
10066        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10067        let mut context_menu = self.context_menu.borrow_mut();
10068        let old_menu = context_menu.take();
10069        *context_menu = Some(CodeContextMenu::Completions(
10070            CompletionsMenu::new_snippet_choices(
10071                id,
10072                true,
10073                choices,
10074                selection,
10075                buffer,
10076                old_menu.map(|menu| menu.primary_scroll_handle()),
10077                snippet_sort_order,
10078            ),
10079        ));
10080    }
10081
10082    pub fn insert_snippet(
10083        &mut self,
10084        insertion_ranges: &[Range<MultiBufferOffset>],
10085        snippet: Snippet,
10086        window: &mut Window,
10087        cx: &mut Context<Self>,
10088    ) -> Result<()> {
10089        struct Tabstop<T> {
10090            is_end_tabstop: bool,
10091            ranges: Vec<Range<T>>,
10092            choices: Option<Vec<String>>,
10093        }
10094
10095        let tabstops = self.buffer.update(cx, |buffer, cx| {
10096            let snippet_text: Arc<str> = snippet.text.clone().into();
10097            let edits = insertion_ranges
10098                .iter()
10099                .cloned()
10100                .map(|range| (range, snippet_text.clone()));
10101            let autoindent_mode = AutoindentMode::Block {
10102                original_indent_columns: Vec::new(),
10103            };
10104            buffer.edit(edits, Some(autoindent_mode), cx);
10105
10106            let snapshot = &*buffer.read(cx);
10107            let snippet = &snippet;
10108            snippet
10109                .tabstops
10110                .iter()
10111                .map(|tabstop| {
10112                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10113                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10114                    });
10115                    let mut tabstop_ranges = tabstop
10116                        .ranges
10117                        .iter()
10118                        .flat_map(|tabstop_range| {
10119                            let mut delta = 0_isize;
10120                            insertion_ranges.iter().map(move |insertion_range| {
10121                                let insertion_start = insertion_range.start + delta;
10122                                delta += snippet.text.len() as isize
10123                                    - (insertion_range.end - insertion_range.start) as isize;
10124
10125                                let start =
10126                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10127                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10128                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10129                            })
10130                        })
10131                        .collect::<Vec<_>>();
10132                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10133
10134                    Tabstop {
10135                        is_end_tabstop,
10136                        ranges: tabstop_ranges,
10137                        choices: tabstop.choices.clone(),
10138                    }
10139                })
10140                .collect::<Vec<_>>()
10141        });
10142        if let Some(tabstop) = tabstops.first() {
10143            self.change_selections(Default::default(), window, cx, |s| {
10144                // Reverse order so that the first range is the newest created selection.
10145                // Completions will use it and autoscroll will prioritize it.
10146                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10147            });
10148
10149            if let Some(choices) = &tabstop.choices
10150                && let Some(selection) = tabstop.ranges.first()
10151            {
10152                self.show_snippet_choices(choices, selection.clone(), cx)
10153            }
10154
10155            // If we're already at the last tabstop and it's at the end of the snippet,
10156            // we're done, we don't need to keep the state around.
10157            if !tabstop.is_end_tabstop {
10158                let choices = tabstops
10159                    .iter()
10160                    .map(|tabstop| tabstop.choices.clone())
10161                    .collect();
10162
10163                let ranges = tabstops
10164                    .into_iter()
10165                    .map(|tabstop| tabstop.ranges)
10166                    .collect::<Vec<_>>();
10167
10168                self.snippet_stack.push(SnippetState {
10169                    active_index: 0,
10170                    ranges,
10171                    choices,
10172                });
10173            }
10174
10175            // Check whether the just-entered snippet ends with an auto-closable bracket.
10176            if self.autoclose_regions.is_empty() {
10177                let snapshot = self.buffer.read(cx).snapshot(cx);
10178                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10179                    let selection_head = selection.head();
10180                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10181                        continue;
10182                    };
10183
10184                    let mut bracket_pair = None;
10185                    let max_lookup_length = scope
10186                        .brackets()
10187                        .map(|(pair, _)| {
10188                            pair.start
10189                                .as_str()
10190                                .chars()
10191                                .count()
10192                                .max(pair.end.as_str().chars().count())
10193                        })
10194                        .max();
10195                    if let Some(max_lookup_length) = max_lookup_length {
10196                        let next_text = snapshot
10197                            .chars_at(selection_head)
10198                            .take(max_lookup_length)
10199                            .collect::<String>();
10200                        let prev_text = snapshot
10201                            .reversed_chars_at(selection_head)
10202                            .take(max_lookup_length)
10203                            .collect::<String>();
10204
10205                        for (pair, enabled) in scope.brackets() {
10206                            if enabled
10207                                && pair.close
10208                                && prev_text.starts_with(pair.start.as_str())
10209                                && next_text.starts_with(pair.end.as_str())
10210                            {
10211                                bracket_pair = Some(pair.clone());
10212                                break;
10213                            }
10214                        }
10215                    }
10216
10217                    if let Some(pair) = bracket_pair {
10218                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10219                        let autoclose_enabled =
10220                            self.use_autoclose && snapshot_settings.use_autoclose;
10221                        if autoclose_enabled {
10222                            let start = snapshot.anchor_after(selection_head);
10223                            let end = snapshot.anchor_after(selection_head);
10224                            self.autoclose_regions.push(AutocloseRegion {
10225                                selection_id: selection.id,
10226                                range: start..end,
10227                                pair,
10228                            });
10229                        }
10230                    }
10231                }
10232            }
10233        }
10234        Ok(())
10235    }
10236
10237    pub fn move_to_next_snippet_tabstop(
10238        &mut self,
10239        window: &mut Window,
10240        cx: &mut Context<Self>,
10241    ) -> bool {
10242        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10243    }
10244
10245    pub fn move_to_prev_snippet_tabstop(
10246        &mut self,
10247        window: &mut Window,
10248        cx: &mut Context<Self>,
10249    ) -> bool {
10250        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10251    }
10252
10253    pub fn move_to_snippet_tabstop(
10254        &mut self,
10255        bias: Bias,
10256        window: &mut Window,
10257        cx: &mut Context<Self>,
10258    ) -> bool {
10259        if let Some(mut snippet) = self.snippet_stack.pop() {
10260            match bias {
10261                Bias::Left => {
10262                    if snippet.active_index > 0 {
10263                        snippet.active_index -= 1;
10264                    } else {
10265                        self.snippet_stack.push(snippet);
10266                        return false;
10267                    }
10268                }
10269                Bias::Right => {
10270                    if snippet.active_index + 1 < snippet.ranges.len() {
10271                        snippet.active_index += 1;
10272                    } else {
10273                        self.snippet_stack.push(snippet);
10274                        return false;
10275                    }
10276                }
10277            }
10278            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10279                self.change_selections(Default::default(), window, cx, |s| {
10280                    // Reverse order so that the first range is the newest created selection.
10281                    // Completions will use it and autoscroll will prioritize it.
10282                    s.select_ranges(current_ranges.iter().rev().cloned())
10283                });
10284
10285                if let Some(choices) = &snippet.choices[snippet.active_index]
10286                    && let Some(selection) = current_ranges.first()
10287                {
10288                    self.show_snippet_choices(choices, selection.clone(), cx);
10289                }
10290
10291                // If snippet state is not at the last tabstop, push it back on the stack
10292                if snippet.active_index + 1 < snippet.ranges.len() {
10293                    self.snippet_stack.push(snippet);
10294                }
10295                return true;
10296            }
10297        }
10298
10299        false
10300    }
10301
10302    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10303        self.transact(window, cx, |this, window, cx| {
10304            this.select_all(&SelectAll, window, cx);
10305            this.insert("", window, cx);
10306        });
10307    }
10308
10309    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10310        if self.read_only(cx) {
10311            return;
10312        }
10313        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10314        self.transact(window, cx, |this, window, cx| {
10315            this.select_autoclose_pair(window, cx);
10316
10317            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10318
10319            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10320            if !this.linked_edit_ranges.is_empty() {
10321                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10322                let snapshot = this.buffer.read(cx).snapshot(cx);
10323
10324                for selection in selections.iter() {
10325                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10326                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10327                    if selection_start.buffer_id != selection_end.buffer_id {
10328                        continue;
10329                    }
10330                    if let Some(ranges) =
10331                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10332                    {
10333                        for (buffer, entries) in ranges {
10334                            linked_ranges.entry(buffer).or_default().extend(entries);
10335                        }
10336                    }
10337                }
10338            }
10339
10340            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10341            for selection in &mut selections {
10342                if selection.is_empty() {
10343                    let old_head = selection.head();
10344                    let mut new_head =
10345                        movement::left(&display_map, old_head.to_display_point(&display_map))
10346                            .to_point(&display_map);
10347                    if let Some((buffer, line_buffer_range)) = display_map
10348                        .buffer_snapshot()
10349                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10350                    {
10351                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10352                        let indent_len = match indent_size.kind {
10353                            IndentKind::Space => {
10354                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10355                            }
10356                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10357                        };
10358                        if old_head.column <= indent_size.len && old_head.column > 0 {
10359                            let indent_len = indent_len.get();
10360                            new_head = cmp::min(
10361                                new_head,
10362                                MultiBufferPoint::new(
10363                                    old_head.row,
10364                                    ((old_head.column - 1) / indent_len) * indent_len,
10365                                ),
10366                            );
10367                        }
10368                    }
10369
10370                    selection.set_head(new_head, SelectionGoal::None);
10371                }
10372            }
10373
10374            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10375            this.insert("", window, cx);
10376            let empty_str: Arc<str> = Arc::from("");
10377            for (buffer, edits) in linked_ranges {
10378                let snapshot = buffer.read(cx).snapshot();
10379                use text::ToPoint as TP;
10380
10381                let edits = edits
10382                    .into_iter()
10383                    .map(|range| {
10384                        let end_point = TP::to_point(&range.end, &snapshot);
10385                        let mut start_point = TP::to_point(&range.start, &snapshot);
10386
10387                        if end_point == start_point {
10388                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10389                                .saturating_sub(1);
10390                            start_point =
10391                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10392                        };
10393
10394                        (start_point..end_point, empty_str.clone())
10395                    })
10396                    .sorted_by_key(|(range, _)| range.start)
10397                    .collect::<Vec<_>>();
10398                buffer.update(cx, |this, cx| {
10399                    this.edit(edits, None, cx);
10400                })
10401            }
10402            this.refresh_edit_prediction(true, false, window, cx);
10403            refresh_linked_ranges(this, window, cx);
10404        });
10405    }
10406
10407    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10408        if self.read_only(cx) {
10409            return;
10410        }
10411        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10412        self.transact(window, cx, |this, window, cx| {
10413            this.change_selections(Default::default(), window, cx, |s| {
10414                s.move_with(|map, selection| {
10415                    if selection.is_empty() {
10416                        let cursor = movement::right(map, selection.head());
10417                        selection.end = cursor;
10418                        selection.reversed = true;
10419                        selection.goal = SelectionGoal::None;
10420                    }
10421                })
10422            });
10423            this.insert("", window, cx);
10424            this.refresh_edit_prediction(true, false, window, cx);
10425        });
10426    }
10427
10428    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10429        if self.mode.is_single_line() {
10430            cx.propagate();
10431            return;
10432        }
10433
10434        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10435        if self.move_to_prev_snippet_tabstop(window, cx) {
10436            return;
10437        }
10438        self.outdent(&Outdent, window, cx);
10439    }
10440
10441    pub fn next_snippet_tabstop(
10442        &mut self,
10443        _: &NextSnippetTabstop,
10444        window: &mut Window,
10445        cx: &mut Context<Self>,
10446    ) {
10447        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10448            cx.propagate();
10449            return;
10450        }
10451
10452        if self.move_to_next_snippet_tabstop(window, cx) {
10453            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10454            return;
10455        }
10456        cx.propagate();
10457    }
10458
10459    pub fn previous_snippet_tabstop(
10460        &mut self,
10461        _: &PreviousSnippetTabstop,
10462        window: &mut Window,
10463        cx: &mut Context<Self>,
10464    ) {
10465        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10466            cx.propagate();
10467            return;
10468        }
10469
10470        if self.move_to_prev_snippet_tabstop(window, cx) {
10471            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10472            return;
10473        }
10474        cx.propagate();
10475    }
10476
10477    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10478        if self.mode.is_single_line() {
10479            cx.propagate();
10480            return;
10481        }
10482
10483        if self.move_to_next_snippet_tabstop(window, cx) {
10484            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10485            return;
10486        }
10487        if self.read_only(cx) {
10488            return;
10489        }
10490        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10491        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10492        let buffer = self.buffer.read(cx);
10493        let snapshot = buffer.snapshot(cx);
10494        let rows_iter = selections.iter().map(|s| s.head().row);
10495        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10496
10497        let has_some_cursor_in_whitespace = selections
10498            .iter()
10499            .filter(|selection| selection.is_empty())
10500            .any(|selection| {
10501                let cursor = selection.head();
10502                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10503                cursor.column < current_indent.len
10504            });
10505
10506        let mut edits = Vec::new();
10507        let mut prev_edited_row = 0;
10508        let mut row_delta = 0;
10509        for selection in &mut selections {
10510            if selection.start.row != prev_edited_row {
10511                row_delta = 0;
10512            }
10513            prev_edited_row = selection.end.row;
10514
10515            // If cursor is after a list prefix, make selection non-empty to trigger line indent
10516            if selection.is_empty() {
10517                let cursor = selection.head();
10518                let settings = buffer.language_settings_at(cursor, cx);
10519                if settings.indent_list_on_tab {
10520                    if let Some(language) = snapshot.language_scope_at(Point::new(cursor.row, 0)) {
10521                        if is_list_prefix_row(MultiBufferRow(cursor.row), &snapshot, &language) {
10522                            row_delta = Self::indent_selection(
10523                                buffer, &snapshot, selection, &mut edits, row_delta, cx,
10524                            );
10525                            continue;
10526                        }
10527                    }
10528                }
10529            }
10530
10531            // If the selection is non-empty, then increase the indentation of the selected lines.
10532            if !selection.is_empty() {
10533                row_delta =
10534                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10535                continue;
10536            }
10537
10538            let cursor = selection.head();
10539            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10540            if let Some(suggested_indent) =
10541                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10542            {
10543                // Don't do anything if already at suggested indent
10544                // and there is any other cursor which is not
10545                if has_some_cursor_in_whitespace
10546                    && cursor.column == current_indent.len
10547                    && current_indent.len == suggested_indent.len
10548                {
10549                    continue;
10550                }
10551
10552                // Adjust line and move cursor to suggested indent
10553                // if cursor is not at suggested indent
10554                if cursor.column < suggested_indent.len
10555                    && cursor.column <= current_indent.len
10556                    && current_indent.len <= suggested_indent.len
10557                {
10558                    selection.start = Point::new(cursor.row, suggested_indent.len);
10559                    selection.end = selection.start;
10560                    if row_delta == 0 {
10561                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10562                            cursor.row,
10563                            current_indent,
10564                            suggested_indent,
10565                        ));
10566                        row_delta = suggested_indent.len - current_indent.len;
10567                    }
10568                    continue;
10569                }
10570
10571                // If current indent is more than suggested indent
10572                // only move cursor to current indent and skip indent
10573                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10574                    selection.start = Point::new(cursor.row, current_indent.len);
10575                    selection.end = selection.start;
10576                    continue;
10577                }
10578            }
10579
10580            // Otherwise, insert a hard or soft tab.
10581            let settings = buffer.language_settings_at(cursor, cx);
10582            let tab_size = if settings.hard_tabs {
10583                IndentSize::tab()
10584            } else {
10585                let tab_size = settings.tab_size.get();
10586                let indent_remainder = snapshot
10587                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10588                    .flat_map(str::chars)
10589                    .fold(row_delta % tab_size, |counter: u32, c| {
10590                        if c == '\t' {
10591                            0
10592                        } else {
10593                            (counter + 1) % tab_size
10594                        }
10595                    });
10596
10597                let chars_to_next_tab_stop = tab_size - indent_remainder;
10598                IndentSize::spaces(chars_to_next_tab_stop)
10599            };
10600            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10601            selection.end = selection.start;
10602            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10603            row_delta += tab_size.len;
10604        }
10605
10606        self.transact(window, cx, |this, window, cx| {
10607            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10608            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10609            this.refresh_edit_prediction(true, false, window, cx);
10610        });
10611    }
10612
10613    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10614        if self.read_only(cx) {
10615            return;
10616        }
10617        if self.mode.is_single_line() {
10618            cx.propagate();
10619            return;
10620        }
10621
10622        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10623        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10624        let mut prev_edited_row = 0;
10625        let mut row_delta = 0;
10626        let mut edits = Vec::new();
10627        let buffer = self.buffer.read(cx);
10628        let snapshot = buffer.snapshot(cx);
10629        for selection in &mut selections {
10630            if selection.start.row != prev_edited_row {
10631                row_delta = 0;
10632            }
10633            prev_edited_row = selection.end.row;
10634
10635            row_delta =
10636                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10637        }
10638
10639        self.transact(window, cx, |this, window, cx| {
10640            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10641            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10642        });
10643    }
10644
10645    fn indent_selection(
10646        buffer: &MultiBuffer,
10647        snapshot: &MultiBufferSnapshot,
10648        selection: &mut Selection<Point>,
10649        edits: &mut Vec<(Range<Point>, String)>,
10650        delta_for_start_row: u32,
10651        cx: &App,
10652    ) -> u32 {
10653        let settings = buffer.language_settings_at(selection.start, cx);
10654        let tab_size = settings.tab_size.get();
10655        let indent_kind = if settings.hard_tabs {
10656            IndentKind::Tab
10657        } else {
10658            IndentKind::Space
10659        };
10660        let mut start_row = selection.start.row;
10661        let mut end_row = selection.end.row + 1;
10662
10663        // If a selection ends at the beginning of a line, don't indent
10664        // that last line.
10665        if selection.end.column == 0 && selection.end.row > selection.start.row {
10666            end_row -= 1;
10667        }
10668
10669        // Avoid re-indenting a row that has already been indented by a
10670        // previous selection, but still update this selection's column
10671        // to reflect that indentation.
10672        if delta_for_start_row > 0 {
10673            start_row += 1;
10674            selection.start.column += delta_for_start_row;
10675            if selection.end.row == selection.start.row {
10676                selection.end.column += delta_for_start_row;
10677            }
10678        }
10679
10680        let mut delta_for_end_row = 0;
10681        let has_multiple_rows = start_row + 1 != end_row;
10682        for row in start_row..end_row {
10683            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10684            let indent_delta = match (current_indent.kind, indent_kind) {
10685                (IndentKind::Space, IndentKind::Space) => {
10686                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10687                    IndentSize::spaces(columns_to_next_tab_stop)
10688                }
10689                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10690                (_, IndentKind::Tab) => IndentSize::tab(),
10691            };
10692
10693            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10694                0
10695            } else {
10696                selection.start.column
10697            };
10698            let row_start = Point::new(row, start);
10699            edits.push((
10700                row_start..row_start,
10701                indent_delta.chars().collect::<String>(),
10702            ));
10703
10704            // Update this selection's endpoints to reflect the indentation.
10705            if row == selection.start.row {
10706                selection.start.column += indent_delta.len;
10707            }
10708            if row == selection.end.row {
10709                selection.end.column += indent_delta.len;
10710                delta_for_end_row = indent_delta.len;
10711            }
10712        }
10713
10714        if selection.start.row == selection.end.row {
10715            delta_for_start_row + delta_for_end_row
10716        } else {
10717            delta_for_end_row
10718        }
10719    }
10720
10721    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10722        if self.read_only(cx) {
10723            return;
10724        }
10725        if self.mode.is_single_line() {
10726            cx.propagate();
10727            return;
10728        }
10729
10730        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10731        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10732        let selections = self.selections.all::<Point>(&display_map);
10733        let mut deletion_ranges = Vec::new();
10734        let mut last_outdent = None;
10735        {
10736            let buffer = self.buffer.read(cx);
10737            let snapshot = buffer.snapshot(cx);
10738            for selection in &selections {
10739                let settings = buffer.language_settings_at(selection.start, cx);
10740                let tab_size = settings.tab_size.get();
10741                let mut rows = selection.spanned_rows(false, &display_map);
10742
10743                // Avoid re-outdenting a row that has already been outdented by a
10744                // previous selection.
10745                if let Some(last_row) = last_outdent
10746                    && last_row == rows.start
10747                {
10748                    rows.start = rows.start.next_row();
10749                }
10750                let has_multiple_rows = rows.len() > 1;
10751                for row in rows.iter_rows() {
10752                    let indent_size = snapshot.indent_size_for_line(row);
10753                    if indent_size.len > 0 {
10754                        let deletion_len = match indent_size.kind {
10755                            IndentKind::Space => {
10756                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10757                                if columns_to_prev_tab_stop == 0 {
10758                                    tab_size
10759                                } else {
10760                                    columns_to_prev_tab_stop
10761                                }
10762                            }
10763                            IndentKind::Tab => 1,
10764                        };
10765                        let start = if has_multiple_rows
10766                            || deletion_len > selection.start.column
10767                            || indent_size.len < selection.start.column
10768                        {
10769                            0
10770                        } else {
10771                            selection.start.column - deletion_len
10772                        };
10773                        deletion_ranges.push(
10774                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10775                        );
10776                        last_outdent = Some(row);
10777                    }
10778                }
10779            }
10780        }
10781
10782        self.transact(window, cx, |this, window, cx| {
10783            this.buffer.update(cx, |buffer, cx| {
10784                let empty_str: Arc<str> = Arc::default();
10785                buffer.edit(
10786                    deletion_ranges
10787                        .into_iter()
10788                        .map(|range| (range, empty_str.clone())),
10789                    None,
10790                    cx,
10791                );
10792            });
10793            let selections = this
10794                .selections
10795                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10796            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10797        });
10798    }
10799
10800    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10801        if self.read_only(cx) {
10802            return;
10803        }
10804        if self.mode.is_single_line() {
10805            cx.propagate();
10806            return;
10807        }
10808
10809        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10810        let selections = self
10811            .selections
10812            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10813            .into_iter()
10814            .map(|s| s.range());
10815
10816        self.transact(window, cx, |this, window, cx| {
10817            this.buffer.update(cx, |buffer, cx| {
10818                buffer.autoindent_ranges(selections, cx);
10819            });
10820            let selections = this
10821                .selections
10822                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10823            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10824        });
10825    }
10826
10827    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10828        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10829        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10830        let selections = self.selections.all::<Point>(&display_map);
10831
10832        let mut new_cursors = Vec::new();
10833        let mut edit_ranges = Vec::new();
10834        let mut selections = selections.iter().peekable();
10835        while let Some(selection) = selections.next() {
10836            let mut rows = selection.spanned_rows(false, &display_map);
10837
10838            // Accumulate contiguous regions of rows that we want to delete.
10839            while let Some(next_selection) = selections.peek() {
10840                let next_rows = next_selection.spanned_rows(false, &display_map);
10841                if next_rows.start <= rows.end {
10842                    rows.end = next_rows.end;
10843                    selections.next().unwrap();
10844                } else {
10845                    break;
10846                }
10847            }
10848
10849            let buffer = display_map.buffer_snapshot();
10850            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10851            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10852                // If there's a line after the range, delete the \n from the end of the row range
10853                (
10854                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10855                    rows.end,
10856                )
10857            } else {
10858                // If there isn't a line after the range, delete the \n from the line before the
10859                // start of the row range
10860                edit_start = edit_start.saturating_sub_usize(1);
10861                (buffer.len(), rows.start.previous_row())
10862            };
10863
10864            let text_layout_details = self.text_layout_details(window);
10865            let x = display_map.x_for_display_point(
10866                selection.head().to_display_point(&display_map),
10867                &text_layout_details,
10868            );
10869            let row = Point::new(target_row.0, 0)
10870                .to_display_point(&display_map)
10871                .row();
10872            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10873
10874            new_cursors.push((
10875                selection.id,
10876                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10877                SelectionGoal::None,
10878            ));
10879            edit_ranges.push(edit_start..edit_end);
10880        }
10881
10882        self.transact(window, cx, |this, window, cx| {
10883            let buffer = this.buffer.update(cx, |buffer, cx| {
10884                let empty_str: Arc<str> = Arc::default();
10885                buffer.edit(
10886                    edit_ranges
10887                        .into_iter()
10888                        .map(|range| (range, empty_str.clone())),
10889                    None,
10890                    cx,
10891                );
10892                buffer.snapshot(cx)
10893            });
10894            let new_selections = new_cursors
10895                .into_iter()
10896                .map(|(id, cursor, goal)| {
10897                    let cursor = cursor.to_point(&buffer);
10898                    Selection {
10899                        id,
10900                        start: cursor,
10901                        end: cursor,
10902                        reversed: false,
10903                        goal,
10904                    }
10905                })
10906                .collect();
10907
10908            this.change_selections(Default::default(), window, cx, |s| {
10909                s.select(new_selections);
10910            });
10911        });
10912    }
10913
10914    pub fn join_lines_impl(
10915        &mut self,
10916        insert_whitespace: bool,
10917        window: &mut Window,
10918        cx: &mut Context<Self>,
10919    ) {
10920        if self.read_only(cx) {
10921            return;
10922        }
10923        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10924        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10925            let start = MultiBufferRow(selection.start.row);
10926            // Treat single line selections as if they include the next line. Otherwise this action
10927            // would do nothing for single line selections individual cursors.
10928            let end = if selection.start.row == selection.end.row {
10929                MultiBufferRow(selection.start.row + 1)
10930            } else {
10931                MultiBufferRow(selection.end.row)
10932            };
10933
10934            if let Some(last_row_range) = row_ranges.last_mut()
10935                && start <= last_row_range.end
10936            {
10937                last_row_range.end = end;
10938                continue;
10939            }
10940            row_ranges.push(start..end);
10941        }
10942
10943        let snapshot = self.buffer.read(cx).snapshot(cx);
10944        let mut cursor_positions = Vec::new();
10945        for row_range in &row_ranges {
10946            let anchor = snapshot.anchor_before(Point::new(
10947                row_range.end.previous_row().0,
10948                snapshot.line_len(row_range.end.previous_row()),
10949            ));
10950            cursor_positions.push(anchor..anchor);
10951        }
10952
10953        self.transact(window, cx, |this, window, cx| {
10954            for row_range in row_ranges.into_iter().rev() {
10955                for row in row_range.iter_rows().rev() {
10956                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10957                    let next_line_row = row.next_row();
10958                    let indent = snapshot.indent_size_for_line(next_line_row);
10959                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10960
10961                    let replace =
10962                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10963                            " "
10964                        } else {
10965                            ""
10966                        };
10967
10968                    this.buffer.update(cx, |buffer, cx| {
10969                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10970                    });
10971                }
10972            }
10973
10974            this.change_selections(Default::default(), window, cx, |s| {
10975                s.select_anchor_ranges(cursor_positions)
10976            });
10977        });
10978    }
10979
10980    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10981        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10982        self.join_lines_impl(true, window, cx);
10983    }
10984
10985    pub fn sort_lines_case_sensitive(
10986        &mut self,
10987        _: &SortLinesCaseSensitive,
10988        window: &mut Window,
10989        cx: &mut Context<Self>,
10990    ) {
10991        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10992    }
10993
10994    pub fn sort_lines_by_length(
10995        &mut self,
10996        _: &SortLinesByLength,
10997        window: &mut Window,
10998        cx: &mut Context<Self>,
10999    ) {
11000        self.manipulate_immutable_lines(window, cx, |lines| {
11001            lines.sort_by_key(|&line| line.chars().count())
11002        })
11003    }
11004
11005    pub fn sort_lines_case_insensitive(
11006        &mut self,
11007        _: &SortLinesCaseInsensitive,
11008        window: &mut Window,
11009        cx: &mut Context<Self>,
11010    ) {
11011        self.manipulate_immutable_lines(window, cx, |lines| {
11012            lines.sort_by_key(|line| line.to_lowercase())
11013        })
11014    }
11015
11016    pub fn unique_lines_case_insensitive(
11017        &mut self,
11018        _: &UniqueLinesCaseInsensitive,
11019        window: &mut Window,
11020        cx: &mut Context<Self>,
11021    ) {
11022        self.manipulate_immutable_lines(window, cx, |lines| {
11023            let mut seen = HashSet::default();
11024            lines.retain(|line| seen.insert(line.to_lowercase()));
11025        })
11026    }
11027
11028    pub fn unique_lines_case_sensitive(
11029        &mut self,
11030        _: &UniqueLinesCaseSensitive,
11031        window: &mut Window,
11032        cx: &mut Context<Self>,
11033    ) {
11034        self.manipulate_immutable_lines(window, cx, |lines| {
11035            let mut seen = HashSet::default();
11036            lines.retain(|line| seen.insert(*line));
11037        })
11038    }
11039
11040    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11041        let snapshot = self.buffer.read(cx).snapshot(cx);
11042        for selection in self.selections.disjoint_anchors_arc().iter() {
11043            if snapshot
11044                .language_at(selection.start)
11045                .and_then(|lang| lang.config().wrap_characters.as_ref())
11046                .is_some()
11047            {
11048                return true;
11049            }
11050        }
11051        false
11052    }
11053
11054    fn wrap_selections_in_tag(
11055        &mut self,
11056        _: &WrapSelectionsInTag,
11057        window: &mut Window,
11058        cx: &mut Context<Self>,
11059    ) {
11060        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11061
11062        let snapshot = self.buffer.read(cx).snapshot(cx);
11063
11064        let mut edits = Vec::new();
11065        let mut boundaries = Vec::new();
11066
11067        for selection in self
11068            .selections
11069            .all_adjusted(&self.display_snapshot(cx))
11070            .iter()
11071        {
11072            let Some(wrap_config) = snapshot
11073                .language_at(selection.start)
11074                .and_then(|lang| lang.config().wrap_characters.clone())
11075            else {
11076                continue;
11077            };
11078
11079            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11080            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11081
11082            let start_before = snapshot.anchor_before(selection.start);
11083            let end_after = snapshot.anchor_after(selection.end);
11084
11085            edits.push((start_before..start_before, open_tag));
11086            edits.push((end_after..end_after, close_tag));
11087
11088            boundaries.push((
11089                start_before,
11090                end_after,
11091                wrap_config.start_prefix.len(),
11092                wrap_config.end_suffix.len(),
11093            ));
11094        }
11095
11096        if edits.is_empty() {
11097            return;
11098        }
11099
11100        self.transact(window, cx, |this, window, cx| {
11101            let buffer = this.buffer.update(cx, |buffer, cx| {
11102                buffer.edit(edits, None, cx);
11103                buffer.snapshot(cx)
11104            });
11105
11106            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11107            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11108                boundaries.into_iter()
11109            {
11110                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11111                let close_offset = end_after
11112                    .to_offset(&buffer)
11113                    .saturating_sub_usize(end_suffix_len);
11114                new_selections.push(open_offset..open_offset);
11115                new_selections.push(close_offset..close_offset);
11116            }
11117
11118            this.change_selections(Default::default(), window, cx, |s| {
11119                s.select_ranges(new_selections);
11120            });
11121
11122            this.request_autoscroll(Autoscroll::fit(), cx);
11123        });
11124    }
11125
11126    pub fn toggle_read_only(
11127        &mut self,
11128        _: &workspace::ToggleReadOnlyFile,
11129        _: &mut Window,
11130        cx: &mut Context<Self>,
11131    ) {
11132        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
11133            buffer.update(cx, |buffer, cx| {
11134                buffer.set_capability(
11135                    match buffer.capability() {
11136                        Capability::ReadWrite => Capability::Read,
11137                        Capability::Read => Capability::ReadWrite,
11138                        Capability::ReadOnly => Capability::ReadOnly,
11139                    },
11140                    cx,
11141                );
11142            })
11143        }
11144    }
11145
11146    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11147        let Some(project) = self.project.clone() else {
11148            return;
11149        };
11150        self.reload(project, window, cx)
11151            .detach_and_notify_err(window, cx);
11152    }
11153
11154    pub fn restore_file(
11155        &mut self,
11156        _: &::git::RestoreFile,
11157        window: &mut Window,
11158        cx: &mut Context<Self>,
11159    ) {
11160        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11161        let mut buffer_ids = HashSet::default();
11162        let snapshot = self.buffer().read(cx).snapshot(cx);
11163        for selection in self
11164            .selections
11165            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11166        {
11167            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11168        }
11169
11170        let buffer = self.buffer().read(cx);
11171        let ranges = buffer_ids
11172            .into_iter()
11173            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11174            .collect::<Vec<_>>();
11175
11176        self.restore_hunks_in_ranges(ranges, window, cx);
11177    }
11178
11179    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11180        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11181        let selections = self
11182            .selections
11183            .all(&self.display_snapshot(cx))
11184            .into_iter()
11185            .map(|s| s.range())
11186            .collect();
11187        self.restore_hunks_in_ranges(selections, window, cx);
11188    }
11189
11190    pub fn restore_hunks_in_ranges(
11191        &mut self,
11192        ranges: Vec<Range<Point>>,
11193        window: &mut Window,
11194        cx: &mut Context<Editor>,
11195    ) {
11196        let mut revert_changes = HashMap::default();
11197        let chunk_by = self
11198            .snapshot(window, cx)
11199            .hunks_for_ranges(ranges)
11200            .into_iter()
11201            .chunk_by(|hunk| hunk.buffer_id);
11202        for (buffer_id, hunks) in &chunk_by {
11203            let hunks = hunks.collect::<Vec<_>>();
11204            for hunk in &hunks {
11205                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11206            }
11207            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11208        }
11209        drop(chunk_by);
11210        if !revert_changes.is_empty() {
11211            self.transact(window, cx, |editor, window, cx| {
11212                editor.restore(revert_changes, window, cx);
11213            });
11214        }
11215    }
11216
11217    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11218        if let Some(status) = self
11219            .addons
11220            .iter()
11221            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11222        {
11223            return Some(status);
11224        }
11225        self.project
11226            .as_ref()?
11227            .read(cx)
11228            .status_for_buffer_id(buffer_id, cx)
11229    }
11230
11231    pub fn open_active_item_in_terminal(
11232        &mut self,
11233        _: &OpenInTerminal,
11234        window: &mut Window,
11235        cx: &mut Context<Self>,
11236    ) {
11237        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11238            let project_path = buffer.read(cx).project_path(cx)?;
11239            let project = self.project()?.read(cx);
11240            let entry = project.entry_for_path(&project_path, cx)?;
11241            let parent = match &entry.canonical_path {
11242                Some(canonical_path) => canonical_path.to_path_buf(),
11243                None => project.absolute_path(&project_path, cx)?,
11244            }
11245            .parent()?
11246            .to_path_buf();
11247            Some(parent)
11248        }) {
11249            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11250        }
11251    }
11252
11253    fn set_breakpoint_context_menu(
11254        &mut self,
11255        display_row: DisplayRow,
11256        position: Option<Anchor>,
11257        clicked_point: gpui::Point<Pixels>,
11258        window: &mut Window,
11259        cx: &mut Context<Self>,
11260    ) {
11261        let source = self
11262            .buffer
11263            .read(cx)
11264            .snapshot(cx)
11265            .anchor_before(Point::new(display_row.0, 0u32));
11266
11267        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11268
11269        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11270            self,
11271            source,
11272            clicked_point,
11273            context_menu,
11274            window,
11275            cx,
11276        );
11277    }
11278
11279    fn add_edit_breakpoint_block(
11280        &mut self,
11281        anchor: Anchor,
11282        breakpoint: &Breakpoint,
11283        edit_action: BreakpointPromptEditAction,
11284        window: &mut Window,
11285        cx: &mut Context<Self>,
11286    ) {
11287        let weak_editor = cx.weak_entity();
11288        let bp_prompt = cx.new(|cx| {
11289            BreakpointPromptEditor::new(
11290                weak_editor,
11291                anchor,
11292                breakpoint.clone(),
11293                edit_action,
11294                window,
11295                cx,
11296            )
11297        });
11298
11299        let height = bp_prompt.update(cx, |this, cx| {
11300            this.prompt
11301                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11302        });
11303        let cloned_prompt = bp_prompt.clone();
11304        let blocks = vec![BlockProperties {
11305            style: BlockStyle::Sticky,
11306            placement: BlockPlacement::Above(anchor),
11307            height: Some(height),
11308            render: Arc::new(move |cx| {
11309                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11310                cloned_prompt.clone().into_any_element()
11311            }),
11312            priority: 0,
11313        }];
11314
11315        let focus_handle = bp_prompt.focus_handle(cx);
11316        window.focus(&focus_handle, cx);
11317
11318        let block_ids = self.insert_blocks(blocks, None, cx);
11319        bp_prompt.update(cx, |prompt, _| {
11320            prompt.add_block_ids(block_ids);
11321        });
11322    }
11323
11324    pub(crate) fn breakpoint_at_row(
11325        &self,
11326        row: u32,
11327        window: &mut Window,
11328        cx: &mut Context<Self>,
11329    ) -> Option<(Anchor, Breakpoint)> {
11330        let snapshot = self.snapshot(window, cx);
11331        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11332
11333        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11334    }
11335
11336    pub(crate) fn breakpoint_at_anchor(
11337        &self,
11338        breakpoint_position: Anchor,
11339        snapshot: &EditorSnapshot,
11340        cx: &mut Context<Self>,
11341    ) -> Option<(Anchor, Breakpoint)> {
11342        let buffer = self
11343            .buffer
11344            .read(cx)
11345            .buffer_for_anchor(breakpoint_position, cx)?;
11346
11347        let enclosing_excerpt = breakpoint_position.excerpt_id;
11348        let buffer_snapshot = buffer.read(cx).snapshot();
11349
11350        let row = buffer_snapshot
11351            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11352            .row;
11353
11354        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11355        let anchor_end = snapshot
11356            .buffer_snapshot()
11357            .anchor_after(Point::new(row, line_len));
11358
11359        self.breakpoint_store
11360            .as_ref()?
11361            .read_with(cx, |breakpoint_store, cx| {
11362                breakpoint_store
11363                    .breakpoints(
11364                        &buffer,
11365                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11366                        &buffer_snapshot,
11367                        cx,
11368                    )
11369                    .next()
11370                    .and_then(|(bp, _)| {
11371                        let breakpoint_row = buffer_snapshot
11372                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11373                            .row;
11374
11375                        if breakpoint_row == row {
11376                            snapshot
11377                                .buffer_snapshot()
11378                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11379                                .map(|position| (position, bp.bp.clone()))
11380                        } else {
11381                            None
11382                        }
11383                    })
11384            })
11385    }
11386
11387    pub fn edit_log_breakpoint(
11388        &mut self,
11389        _: &EditLogBreakpoint,
11390        window: &mut Window,
11391        cx: &mut Context<Self>,
11392    ) {
11393        if self.breakpoint_store.is_none() {
11394            return;
11395        }
11396
11397        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11398            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11399                message: None,
11400                state: BreakpointState::Enabled,
11401                condition: None,
11402                hit_condition: None,
11403            });
11404
11405            self.add_edit_breakpoint_block(
11406                anchor,
11407                &breakpoint,
11408                BreakpointPromptEditAction::Log,
11409                window,
11410                cx,
11411            );
11412        }
11413    }
11414
11415    fn breakpoints_at_cursors(
11416        &self,
11417        window: &mut Window,
11418        cx: &mut Context<Self>,
11419    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11420        let snapshot = self.snapshot(window, cx);
11421        let cursors = self
11422            .selections
11423            .disjoint_anchors_arc()
11424            .iter()
11425            .map(|selection| {
11426                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11427
11428                let breakpoint_position = self
11429                    .breakpoint_at_row(cursor_position.row, window, cx)
11430                    .map(|bp| bp.0)
11431                    .unwrap_or_else(|| {
11432                        snapshot
11433                            .display_snapshot
11434                            .buffer_snapshot()
11435                            .anchor_after(Point::new(cursor_position.row, 0))
11436                    });
11437
11438                let breakpoint = self
11439                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11440                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11441
11442                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11443            })
11444            // 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.
11445            .collect::<HashMap<Anchor, _>>();
11446
11447        cursors.into_iter().collect()
11448    }
11449
11450    pub fn enable_breakpoint(
11451        &mut self,
11452        _: &crate::actions::EnableBreakpoint,
11453        window: &mut Window,
11454        cx: &mut Context<Self>,
11455    ) {
11456        if self.breakpoint_store.is_none() {
11457            return;
11458        }
11459
11460        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11461            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11462                continue;
11463            };
11464            self.edit_breakpoint_at_anchor(
11465                anchor,
11466                breakpoint,
11467                BreakpointEditAction::InvertState,
11468                cx,
11469            );
11470        }
11471    }
11472
11473    pub fn disable_breakpoint(
11474        &mut self,
11475        _: &crate::actions::DisableBreakpoint,
11476        window: &mut Window,
11477        cx: &mut Context<Self>,
11478    ) {
11479        if self.breakpoint_store.is_none() {
11480            return;
11481        }
11482
11483        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11484            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11485                continue;
11486            };
11487            self.edit_breakpoint_at_anchor(
11488                anchor,
11489                breakpoint,
11490                BreakpointEditAction::InvertState,
11491                cx,
11492            );
11493        }
11494    }
11495
11496    pub fn toggle_breakpoint(
11497        &mut self,
11498        _: &crate::actions::ToggleBreakpoint,
11499        window: &mut Window,
11500        cx: &mut Context<Self>,
11501    ) {
11502        if self.breakpoint_store.is_none() {
11503            return;
11504        }
11505
11506        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11507            if let Some(breakpoint) = breakpoint {
11508                self.edit_breakpoint_at_anchor(
11509                    anchor,
11510                    breakpoint,
11511                    BreakpointEditAction::Toggle,
11512                    cx,
11513                );
11514            } else {
11515                self.edit_breakpoint_at_anchor(
11516                    anchor,
11517                    Breakpoint::new_standard(),
11518                    BreakpointEditAction::Toggle,
11519                    cx,
11520                );
11521            }
11522        }
11523    }
11524
11525    pub fn edit_breakpoint_at_anchor(
11526        &mut self,
11527        breakpoint_position: Anchor,
11528        breakpoint: Breakpoint,
11529        edit_action: BreakpointEditAction,
11530        cx: &mut Context<Self>,
11531    ) {
11532        let Some(breakpoint_store) = &self.breakpoint_store else {
11533            return;
11534        };
11535
11536        let Some(buffer) = self
11537            .buffer
11538            .read(cx)
11539            .buffer_for_anchor(breakpoint_position, cx)
11540        else {
11541            return;
11542        };
11543
11544        breakpoint_store.update(cx, |breakpoint_store, cx| {
11545            breakpoint_store.toggle_breakpoint(
11546                buffer,
11547                BreakpointWithPosition {
11548                    position: breakpoint_position.text_anchor,
11549                    bp: breakpoint,
11550                },
11551                edit_action,
11552                cx,
11553            );
11554        });
11555
11556        cx.notify();
11557    }
11558
11559    #[cfg(any(test, feature = "test-support"))]
11560    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11561        self.breakpoint_store.clone()
11562    }
11563
11564    pub fn prepare_restore_change(
11565        &self,
11566        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11567        hunk: &MultiBufferDiffHunk,
11568        cx: &mut App,
11569    ) -> Option<()> {
11570        if hunk.is_created_file() {
11571            return None;
11572        }
11573        let buffer = self.buffer.read(cx);
11574        let diff = buffer.diff_for(hunk.buffer_id)?;
11575        let buffer = buffer.buffer(hunk.buffer_id)?;
11576        let buffer = buffer.read(cx);
11577        let original_text = diff
11578            .read(cx)
11579            .base_text(cx)
11580            .as_rope()
11581            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11582        let buffer_snapshot = buffer.snapshot();
11583        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11584        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11585            probe
11586                .0
11587                .start
11588                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11589                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11590        }) {
11591            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11592            Some(())
11593        } else {
11594            None
11595        }
11596    }
11597
11598    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11599        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11600    }
11601
11602    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11603        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11604    }
11605
11606    pub fn rotate_selections_forward(
11607        &mut self,
11608        _: &RotateSelectionsForward,
11609        window: &mut Window,
11610        cx: &mut Context<Self>,
11611    ) {
11612        self.rotate_selections(window, cx, false)
11613    }
11614
11615    pub fn rotate_selections_backward(
11616        &mut self,
11617        _: &RotateSelectionsBackward,
11618        window: &mut Window,
11619        cx: &mut Context<Self>,
11620    ) {
11621        self.rotate_selections(window, cx, true)
11622    }
11623
11624    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11625        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11626        let display_snapshot = self.display_snapshot(cx);
11627        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11628
11629        if selections.len() < 2 {
11630            return;
11631        }
11632
11633        let (edits, new_selections) = {
11634            let buffer = self.buffer.read(cx).read(cx);
11635            let has_selections = selections.iter().any(|s| !s.is_empty());
11636            if has_selections {
11637                let mut selected_texts: Vec<String> = selections
11638                    .iter()
11639                    .map(|selection| {
11640                        buffer
11641                            .text_for_range(selection.start..selection.end)
11642                            .collect()
11643                    })
11644                    .collect();
11645
11646                if reverse {
11647                    selected_texts.rotate_left(1);
11648                } else {
11649                    selected_texts.rotate_right(1);
11650                }
11651
11652                let mut offset_delta: i64 = 0;
11653                let mut new_selections = Vec::new();
11654                let edits: Vec<_> = selections
11655                    .iter()
11656                    .zip(selected_texts.iter())
11657                    .map(|(selection, new_text)| {
11658                        let old_len = (selection.end.0 - selection.start.0) as i64;
11659                        let new_len = new_text.len() as i64;
11660                        let adjusted_start =
11661                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11662                        let adjusted_end =
11663                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11664
11665                        new_selections.push(Selection {
11666                            id: selection.id,
11667                            start: adjusted_start,
11668                            end: adjusted_end,
11669                            reversed: selection.reversed,
11670                            goal: selection.goal,
11671                        });
11672
11673                        offset_delta += new_len - old_len;
11674                        (selection.start..selection.end, new_text.clone())
11675                    })
11676                    .collect();
11677                (edits, new_selections)
11678            } else {
11679                let mut all_rows: Vec<u32> = selections
11680                    .iter()
11681                    .map(|selection| buffer.offset_to_point(selection.start).row)
11682                    .collect();
11683                all_rows.sort_unstable();
11684                all_rows.dedup();
11685
11686                if all_rows.len() < 2 {
11687                    return;
11688                }
11689
11690                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11691                    .iter()
11692                    .map(|&row| {
11693                        let start = Point::new(row, 0);
11694                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11695                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11696                    })
11697                    .collect();
11698
11699                let mut line_texts: Vec<String> = line_ranges
11700                    .iter()
11701                    .map(|range| buffer.text_for_range(range.clone()).collect())
11702                    .collect();
11703
11704                if reverse {
11705                    line_texts.rotate_left(1);
11706                } else {
11707                    line_texts.rotate_right(1);
11708                }
11709
11710                let edits = line_ranges
11711                    .iter()
11712                    .zip(line_texts.iter())
11713                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11714                    .collect();
11715
11716                let num_rows = all_rows.len();
11717                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11718                    .iter()
11719                    .enumerate()
11720                    .map(|(i, &row)| (row, i))
11721                    .collect();
11722
11723                // Compute new line start offsets after rotation (handles CRLF)
11724                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11725                let first_line_start = line_ranges[0].start.0;
11726                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11727                for text in line_texts.iter().take(num_rows - 1) {
11728                    let prev_start = *new_line_starts.last().unwrap();
11729                    new_line_starts.push(prev_start + text.len() + newline_len);
11730                }
11731
11732                let new_selections = selections
11733                    .iter()
11734                    .map(|selection| {
11735                        let point = buffer.offset_to_point(selection.start);
11736                        let old_index = row_to_index[&point.row];
11737                        let new_index = if reverse {
11738                            (old_index + num_rows - 1) % num_rows
11739                        } else {
11740                            (old_index + 1) % num_rows
11741                        };
11742                        let new_offset =
11743                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11744                        Selection {
11745                            id: selection.id,
11746                            start: new_offset,
11747                            end: new_offset,
11748                            reversed: selection.reversed,
11749                            goal: selection.goal,
11750                        }
11751                    })
11752                    .collect();
11753
11754                (edits, new_selections)
11755            }
11756        };
11757
11758        self.transact(window, cx, |this, window, cx| {
11759            this.buffer.update(cx, |buffer, cx| {
11760                buffer.edit(edits, None, cx);
11761            });
11762            this.change_selections(Default::default(), window, cx, |s| {
11763                s.select(new_selections);
11764            });
11765        });
11766    }
11767
11768    fn manipulate_lines<M>(
11769        &mut self,
11770        window: &mut Window,
11771        cx: &mut Context<Self>,
11772        mut manipulate: M,
11773    ) where
11774        M: FnMut(&str) -> LineManipulationResult,
11775    {
11776        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11777
11778        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11779        let buffer = self.buffer.read(cx).snapshot(cx);
11780
11781        let mut edits = Vec::new();
11782
11783        let selections = self.selections.all::<Point>(&display_map);
11784        let mut selections = selections.iter().peekable();
11785        let mut contiguous_row_selections = Vec::new();
11786        let mut new_selections = Vec::new();
11787        let mut added_lines = 0;
11788        let mut removed_lines = 0;
11789
11790        while let Some(selection) = selections.next() {
11791            let (start_row, end_row) = consume_contiguous_rows(
11792                &mut contiguous_row_selections,
11793                selection,
11794                &display_map,
11795                &mut selections,
11796            );
11797
11798            let start_point = Point::new(start_row.0, 0);
11799            let end_point = Point::new(
11800                end_row.previous_row().0,
11801                buffer.line_len(end_row.previous_row()),
11802            );
11803            let text = buffer
11804                .text_for_range(start_point..end_point)
11805                .collect::<String>();
11806
11807            let LineManipulationResult {
11808                new_text,
11809                line_count_before,
11810                line_count_after,
11811            } = manipulate(&text);
11812
11813            edits.push((start_point..end_point, new_text));
11814
11815            // Selections must change based on added and removed line count
11816            let start_row =
11817                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11818            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11819            new_selections.push(Selection {
11820                id: selection.id,
11821                start: start_row,
11822                end: end_row,
11823                goal: SelectionGoal::None,
11824                reversed: selection.reversed,
11825            });
11826
11827            if line_count_after > line_count_before {
11828                added_lines += line_count_after - line_count_before;
11829            } else if line_count_before > line_count_after {
11830                removed_lines += line_count_before - line_count_after;
11831            }
11832        }
11833
11834        self.transact(window, cx, |this, window, cx| {
11835            let buffer = this.buffer.update(cx, |buffer, cx| {
11836                buffer.edit(edits, None, cx);
11837                buffer.snapshot(cx)
11838            });
11839
11840            // Recalculate offsets on newly edited buffer
11841            let new_selections = new_selections
11842                .iter()
11843                .map(|s| {
11844                    let start_point = Point::new(s.start.0, 0);
11845                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11846                    Selection {
11847                        id: s.id,
11848                        start: buffer.point_to_offset(start_point),
11849                        end: buffer.point_to_offset(end_point),
11850                        goal: s.goal,
11851                        reversed: s.reversed,
11852                    }
11853                })
11854                .collect();
11855
11856            this.change_selections(Default::default(), window, cx, |s| {
11857                s.select(new_selections);
11858            });
11859
11860            this.request_autoscroll(Autoscroll::fit(), cx);
11861        });
11862    }
11863
11864    fn manipulate_immutable_lines<Fn>(
11865        &mut self,
11866        window: &mut Window,
11867        cx: &mut Context<Self>,
11868        mut callback: Fn,
11869    ) where
11870        Fn: FnMut(&mut Vec<&str>),
11871    {
11872        self.manipulate_lines(window, cx, |text| {
11873            let mut lines: Vec<&str> = text.split('\n').collect();
11874            let line_count_before = lines.len();
11875
11876            callback(&mut lines);
11877
11878            LineManipulationResult {
11879                new_text: lines.join("\n"),
11880                line_count_before,
11881                line_count_after: lines.len(),
11882            }
11883        });
11884    }
11885
11886    fn manipulate_mutable_lines<Fn>(
11887        &mut self,
11888        window: &mut Window,
11889        cx: &mut Context<Self>,
11890        mut callback: Fn,
11891    ) where
11892        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11893    {
11894        self.manipulate_lines(window, cx, |text| {
11895            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11896            let line_count_before = lines.len();
11897
11898            callback(&mut lines);
11899
11900            LineManipulationResult {
11901                new_text: lines.join("\n"),
11902                line_count_before,
11903                line_count_after: lines.len(),
11904            }
11905        });
11906    }
11907
11908    pub fn convert_indentation_to_spaces(
11909        &mut self,
11910        _: &ConvertIndentationToSpaces,
11911        window: &mut Window,
11912        cx: &mut Context<Self>,
11913    ) {
11914        let settings = self.buffer.read(cx).language_settings(cx);
11915        let tab_size = settings.tab_size.get() as usize;
11916
11917        self.manipulate_mutable_lines(window, cx, |lines| {
11918            // Allocates a reasonably sized scratch buffer once for the whole loop
11919            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11920            // Avoids recomputing spaces that could be inserted many times
11921            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11922                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11923                .collect();
11924
11925            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11926                let mut chars = line.as_ref().chars();
11927                let mut col = 0;
11928                let mut changed = false;
11929
11930                for ch in chars.by_ref() {
11931                    match ch {
11932                        ' ' => {
11933                            reindented_line.push(' ');
11934                            col += 1;
11935                        }
11936                        '\t' => {
11937                            // \t are converted to spaces depending on the current column
11938                            let spaces_len = tab_size - (col % tab_size);
11939                            reindented_line.extend(&space_cache[spaces_len - 1]);
11940                            col += spaces_len;
11941                            changed = true;
11942                        }
11943                        _ => {
11944                            // If we dont append before break, the character is consumed
11945                            reindented_line.push(ch);
11946                            break;
11947                        }
11948                    }
11949                }
11950
11951                if !changed {
11952                    reindented_line.clear();
11953                    continue;
11954                }
11955                // Append the rest of the line and replace old reference with new one
11956                reindented_line.extend(chars);
11957                *line = Cow::Owned(reindented_line.clone());
11958                reindented_line.clear();
11959            }
11960        });
11961    }
11962
11963    pub fn convert_indentation_to_tabs(
11964        &mut self,
11965        _: &ConvertIndentationToTabs,
11966        window: &mut Window,
11967        cx: &mut Context<Self>,
11968    ) {
11969        let settings = self.buffer.read(cx).language_settings(cx);
11970        let tab_size = settings.tab_size.get() as usize;
11971
11972        self.manipulate_mutable_lines(window, cx, |lines| {
11973            // Allocates a reasonably sized buffer once for the whole loop
11974            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11975            // Avoids recomputing spaces that could be inserted many times
11976            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11977                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11978                .collect();
11979
11980            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11981                let mut chars = line.chars();
11982                let mut spaces_count = 0;
11983                let mut first_non_indent_char = None;
11984                let mut changed = false;
11985
11986                for ch in chars.by_ref() {
11987                    match ch {
11988                        ' ' => {
11989                            // Keep track of spaces. Append \t when we reach tab_size
11990                            spaces_count += 1;
11991                            changed = true;
11992                            if spaces_count == tab_size {
11993                                reindented_line.push('\t');
11994                                spaces_count = 0;
11995                            }
11996                        }
11997                        '\t' => {
11998                            reindented_line.push('\t');
11999                            spaces_count = 0;
12000                        }
12001                        _ => {
12002                            // Dont append it yet, we might have remaining spaces
12003                            first_non_indent_char = Some(ch);
12004                            break;
12005                        }
12006                    }
12007                }
12008
12009                if !changed {
12010                    reindented_line.clear();
12011                    continue;
12012                }
12013                // Remaining spaces that didn't make a full tab stop
12014                if spaces_count > 0 {
12015                    reindented_line.extend(&space_cache[spaces_count - 1]);
12016                }
12017                // If we consume an extra character that was not indentation, add it back
12018                if let Some(extra_char) = first_non_indent_char {
12019                    reindented_line.push(extra_char);
12020                }
12021                // Append the rest of the line and replace old reference with new one
12022                reindented_line.extend(chars);
12023                *line = Cow::Owned(reindented_line.clone());
12024                reindented_line.clear();
12025            }
12026        });
12027    }
12028
12029    pub fn convert_to_upper_case(
12030        &mut self,
12031        _: &ConvertToUpperCase,
12032        window: &mut Window,
12033        cx: &mut Context<Self>,
12034    ) {
12035        self.manipulate_text(window, cx, |text| text.to_uppercase())
12036    }
12037
12038    pub fn convert_to_lower_case(
12039        &mut self,
12040        _: &ConvertToLowerCase,
12041        window: &mut Window,
12042        cx: &mut Context<Self>,
12043    ) {
12044        self.manipulate_text(window, cx, |text| text.to_lowercase())
12045    }
12046
12047    pub fn convert_to_title_case(
12048        &mut self,
12049        _: &ConvertToTitleCase,
12050        window: &mut Window,
12051        cx: &mut Context<Self>,
12052    ) {
12053        self.manipulate_text(window, cx, |text| {
12054            text.split('\n')
12055                .map(|line| line.to_case(Case::Title))
12056                .join("\n")
12057        })
12058    }
12059
12060    pub fn convert_to_snake_case(
12061        &mut self,
12062        _: &ConvertToSnakeCase,
12063        window: &mut Window,
12064        cx: &mut Context<Self>,
12065    ) {
12066        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
12067    }
12068
12069    pub fn convert_to_kebab_case(
12070        &mut self,
12071        _: &ConvertToKebabCase,
12072        window: &mut Window,
12073        cx: &mut Context<Self>,
12074    ) {
12075        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
12076    }
12077
12078    pub fn convert_to_upper_camel_case(
12079        &mut self,
12080        _: &ConvertToUpperCamelCase,
12081        window: &mut Window,
12082        cx: &mut Context<Self>,
12083    ) {
12084        self.manipulate_text(window, cx, |text| {
12085            text.split('\n')
12086                .map(|line| line.to_case(Case::UpperCamel))
12087                .join("\n")
12088        })
12089    }
12090
12091    pub fn convert_to_lower_camel_case(
12092        &mut self,
12093        _: &ConvertToLowerCamelCase,
12094        window: &mut Window,
12095        cx: &mut Context<Self>,
12096    ) {
12097        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
12098    }
12099
12100    pub fn convert_to_opposite_case(
12101        &mut self,
12102        _: &ConvertToOppositeCase,
12103        window: &mut Window,
12104        cx: &mut Context<Self>,
12105    ) {
12106        self.manipulate_text(window, cx, |text| {
12107            text.chars()
12108                .fold(String::with_capacity(text.len()), |mut t, c| {
12109                    if c.is_uppercase() {
12110                        t.extend(c.to_lowercase());
12111                    } else {
12112                        t.extend(c.to_uppercase());
12113                    }
12114                    t
12115                })
12116        })
12117    }
12118
12119    pub fn convert_to_sentence_case(
12120        &mut self,
12121        _: &ConvertToSentenceCase,
12122        window: &mut Window,
12123        cx: &mut Context<Self>,
12124    ) {
12125        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12126    }
12127
12128    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12129        self.manipulate_text(window, cx, |text| {
12130            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12131            if has_upper_case_characters {
12132                text.to_lowercase()
12133            } else {
12134                text.to_uppercase()
12135            }
12136        })
12137    }
12138
12139    pub fn convert_to_rot13(
12140        &mut self,
12141        _: &ConvertToRot13,
12142        window: &mut Window,
12143        cx: &mut Context<Self>,
12144    ) {
12145        self.manipulate_text(window, cx, |text| {
12146            text.chars()
12147                .map(|c| match c {
12148                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12149                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12150                    _ => c,
12151                })
12152                .collect()
12153        })
12154    }
12155
12156    pub fn convert_to_rot47(
12157        &mut self,
12158        _: &ConvertToRot47,
12159        window: &mut Window,
12160        cx: &mut Context<Self>,
12161    ) {
12162        self.manipulate_text(window, cx, |text| {
12163            text.chars()
12164                .map(|c| {
12165                    let code_point = c as u32;
12166                    if code_point >= 33 && code_point <= 126 {
12167                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12168                    }
12169                    c
12170                })
12171                .collect()
12172        })
12173    }
12174
12175    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12176    where
12177        Fn: FnMut(&str) -> String,
12178    {
12179        let buffer = self.buffer.read(cx).snapshot(cx);
12180
12181        let mut new_selections = Vec::new();
12182        let mut edits = Vec::new();
12183        let mut selection_adjustment = 0isize;
12184
12185        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12186            let selection_is_empty = selection.is_empty();
12187
12188            let (start, end) = if selection_is_empty {
12189                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12190                (word_range.start, word_range.end)
12191            } else {
12192                (
12193                    buffer.point_to_offset(selection.start),
12194                    buffer.point_to_offset(selection.end),
12195                )
12196            };
12197
12198            let text = buffer.text_for_range(start..end).collect::<String>();
12199            let old_length = text.len() as isize;
12200            let text = callback(&text);
12201
12202            new_selections.push(Selection {
12203                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12204                end: MultiBufferOffset(
12205                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12206                ),
12207                goal: SelectionGoal::None,
12208                id: selection.id,
12209                reversed: selection.reversed,
12210            });
12211
12212            selection_adjustment += old_length - text.len() as isize;
12213
12214            edits.push((start..end, text));
12215        }
12216
12217        self.transact(window, cx, |this, window, cx| {
12218            this.buffer.update(cx, |buffer, cx| {
12219                buffer.edit(edits, None, cx);
12220            });
12221
12222            this.change_selections(Default::default(), window, cx, |s| {
12223                s.select(new_selections);
12224            });
12225
12226            this.request_autoscroll(Autoscroll::fit(), cx);
12227        });
12228    }
12229
12230    pub fn move_selection_on_drop(
12231        &mut self,
12232        selection: &Selection<Anchor>,
12233        target: DisplayPoint,
12234        is_cut: bool,
12235        window: &mut Window,
12236        cx: &mut Context<Self>,
12237    ) {
12238        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12239        let buffer = display_map.buffer_snapshot();
12240        let mut edits = Vec::new();
12241        let insert_point = display_map
12242            .clip_point(target, Bias::Left)
12243            .to_point(&display_map);
12244        let text = buffer
12245            .text_for_range(selection.start..selection.end)
12246            .collect::<String>();
12247        if is_cut {
12248            edits.push(((selection.start..selection.end), String::new()));
12249        }
12250        let insert_anchor = buffer.anchor_before(insert_point);
12251        edits.push(((insert_anchor..insert_anchor), text));
12252        let last_edit_start = insert_anchor.bias_left(buffer);
12253        let last_edit_end = insert_anchor.bias_right(buffer);
12254        self.transact(window, cx, |this, window, cx| {
12255            this.buffer.update(cx, |buffer, cx| {
12256                buffer.edit(edits, None, cx);
12257            });
12258            this.change_selections(Default::default(), window, cx, |s| {
12259                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12260            });
12261        });
12262    }
12263
12264    pub fn clear_selection_drag_state(&mut self) {
12265        self.selection_drag_state = SelectionDragState::None;
12266    }
12267
12268    pub fn duplicate(
12269        &mut self,
12270        upwards: bool,
12271        whole_lines: bool,
12272        window: &mut Window,
12273        cx: &mut Context<Self>,
12274    ) {
12275        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12276
12277        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12278        let buffer = display_map.buffer_snapshot();
12279        let selections = self.selections.all::<Point>(&display_map);
12280
12281        let mut edits = Vec::new();
12282        let mut selections_iter = selections.iter().peekable();
12283        while let Some(selection) = selections_iter.next() {
12284            let mut rows = selection.spanned_rows(false, &display_map);
12285            // duplicate line-wise
12286            if whole_lines || selection.start == selection.end {
12287                // Avoid duplicating the same lines twice.
12288                while let Some(next_selection) = selections_iter.peek() {
12289                    let next_rows = next_selection.spanned_rows(false, &display_map);
12290                    if next_rows.start < rows.end {
12291                        rows.end = next_rows.end;
12292                        selections_iter.next().unwrap();
12293                    } else {
12294                        break;
12295                    }
12296                }
12297
12298                // Copy the text from the selected row region and splice it either at the start
12299                // or end of the region.
12300                let start = Point::new(rows.start.0, 0);
12301                let end = Point::new(
12302                    rows.end.previous_row().0,
12303                    buffer.line_len(rows.end.previous_row()),
12304                );
12305
12306                let mut text = buffer.text_for_range(start..end).collect::<String>();
12307
12308                let insert_location = if upwards {
12309                    // When duplicating upward, we need to insert before the current line.
12310                    // If we're on the last line and it doesn't end with a newline,
12311                    // we need to add a newline before the duplicated content.
12312                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12313                        && buffer.max_point().column > 0
12314                        && !text.ends_with('\n');
12315
12316                    if needs_leading_newline {
12317                        text.insert(0, '\n');
12318                        end
12319                    } else {
12320                        text.push('\n');
12321                        Point::new(rows.start.0, 0)
12322                    }
12323                } else {
12324                    text.push('\n');
12325                    start
12326                };
12327                edits.push((insert_location..insert_location, text));
12328            } else {
12329                // duplicate character-wise
12330                let start = selection.start;
12331                let end = selection.end;
12332                let text = buffer.text_for_range(start..end).collect::<String>();
12333                edits.push((selection.end..selection.end, text));
12334            }
12335        }
12336
12337        self.transact(window, cx, |this, window, cx| {
12338            this.buffer.update(cx, |buffer, cx| {
12339                buffer.edit(edits, None, cx);
12340            });
12341
12342            // When duplicating upward with whole lines, move the cursor to the duplicated line
12343            if upwards && whole_lines {
12344                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12345
12346                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12347                    let mut new_ranges = Vec::new();
12348                    let selections = s.all::<Point>(&display_map);
12349                    let mut selections_iter = selections.iter().peekable();
12350
12351                    while let Some(first_selection) = selections_iter.next() {
12352                        // Group contiguous selections together to find the total row span
12353                        let mut group_selections = vec![first_selection];
12354                        let mut rows = first_selection.spanned_rows(false, &display_map);
12355
12356                        while let Some(next_selection) = selections_iter.peek() {
12357                            let next_rows = next_selection.spanned_rows(false, &display_map);
12358                            if next_rows.start < rows.end {
12359                                rows.end = next_rows.end;
12360                                group_selections.push(selections_iter.next().unwrap());
12361                            } else {
12362                                break;
12363                            }
12364                        }
12365
12366                        let row_count = rows.end.0 - rows.start.0;
12367
12368                        // Move all selections in this group up by the total number of duplicated rows
12369                        for selection in group_selections {
12370                            let new_start = Point::new(
12371                                selection.start.row.saturating_sub(row_count),
12372                                selection.start.column,
12373                            );
12374
12375                            let new_end = Point::new(
12376                                selection.end.row.saturating_sub(row_count),
12377                                selection.end.column,
12378                            );
12379
12380                            new_ranges.push(new_start..new_end);
12381                        }
12382                    }
12383
12384                    s.select_ranges(new_ranges);
12385                });
12386            }
12387
12388            this.request_autoscroll(Autoscroll::fit(), cx);
12389        });
12390    }
12391
12392    pub fn duplicate_line_up(
12393        &mut self,
12394        _: &DuplicateLineUp,
12395        window: &mut Window,
12396        cx: &mut Context<Self>,
12397    ) {
12398        self.duplicate(true, true, window, cx);
12399    }
12400
12401    pub fn duplicate_line_down(
12402        &mut self,
12403        _: &DuplicateLineDown,
12404        window: &mut Window,
12405        cx: &mut Context<Self>,
12406    ) {
12407        self.duplicate(false, true, window, cx);
12408    }
12409
12410    pub fn duplicate_selection(
12411        &mut self,
12412        _: &DuplicateSelection,
12413        window: &mut Window,
12414        cx: &mut Context<Self>,
12415    ) {
12416        self.duplicate(false, false, window, cx);
12417    }
12418
12419    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12420        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12421        if self.mode.is_single_line() {
12422            cx.propagate();
12423            return;
12424        }
12425
12426        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12427        let buffer = self.buffer.read(cx).snapshot(cx);
12428
12429        let mut edits = Vec::new();
12430        let mut unfold_ranges = Vec::new();
12431        let mut refold_creases = Vec::new();
12432
12433        let selections = self.selections.all::<Point>(&display_map);
12434        let mut selections = selections.iter().peekable();
12435        let mut contiguous_row_selections = Vec::new();
12436        let mut new_selections = Vec::new();
12437
12438        while let Some(selection) = selections.next() {
12439            // Find all the selections that span a contiguous row range
12440            let (start_row, end_row) = consume_contiguous_rows(
12441                &mut contiguous_row_selections,
12442                selection,
12443                &display_map,
12444                &mut selections,
12445            );
12446
12447            // Move the text spanned by the row range to be before the line preceding the row range
12448            if start_row.0 > 0 {
12449                let range_to_move = Point::new(
12450                    start_row.previous_row().0,
12451                    buffer.line_len(start_row.previous_row()),
12452                )
12453                    ..Point::new(
12454                        end_row.previous_row().0,
12455                        buffer.line_len(end_row.previous_row()),
12456                    );
12457                let insertion_point = display_map
12458                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12459                    .0;
12460
12461                // Don't move lines across excerpts
12462                if buffer
12463                    .excerpt_containing(insertion_point..range_to_move.end)
12464                    .is_some()
12465                {
12466                    let text = buffer
12467                        .text_for_range(range_to_move.clone())
12468                        .flat_map(|s| s.chars())
12469                        .skip(1)
12470                        .chain(['\n'])
12471                        .collect::<String>();
12472
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 = range_to_move.start.row - insertion_point.row + 1;
12482
12483                    // Move selections up
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 up
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| {
12520                s.select(new_selections);
12521            })
12522        });
12523    }
12524
12525    pub fn move_line_down(
12526        &mut self,
12527        _: &MoveLineDown,
12528        window: &mut Window,
12529        cx: &mut Context<Self>,
12530    ) {
12531        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12532        if self.mode.is_single_line() {
12533            cx.propagate();
12534            return;
12535        }
12536
12537        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12538        let buffer = self.buffer.read(cx).snapshot(cx);
12539
12540        let mut edits = Vec::new();
12541        let mut unfold_ranges = Vec::new();
12542        let mut refold_creases = Vec::new();
12543
12544        let selections = self.selections.all::<Point>(&display_map);
12545        let mut selections = selections.iter().peekable();
12546        let mut contiguous_row_selections = Vec::new();
12547        let mut new_selections = Vec::new();
12548
12549        while let Some(selection) = selections.next() {
12550            // Find all the selections that span a contiguous row range
12551            let (start_row, end_row) = consume_contiguous_rows(
12552                &mut contiguous_row_selections,
12553                selection,
12554                &display_map,
12555                &mut selections,
12556            );
12557
12558            // Move the text spanned by the row range to be after the last line of the row range
12559            if end_row.0 <= buffer.max_point().row {
12560                let range_to_move =
12561                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12562                let insertion_point = display_map
12563                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12564                    .0;
12565
12566                // Don't move lines across excerpt boundaries
12567                if buffer
12568                    .excerpt_containing(range_to_move.start..insertion_point)
12569                    .is_some()
12570                {
12571                    let mut text = String::from("\n");
12572                    text.extend(buffer.text_for_range(range_to_move.clone()));
12573                    text.pop(); // Drop trailing newline
12574                    edits.push((
12575                        buffer.anchor_after(range_to_move.start)
12576                            ..buffer.anchor_before(range_to_move.end),
12577                        String::new(),
12578                    ));
12579                    let insertion_anchor = buffer.anchor_after(insertion_point);
12580                    edits.push((insertion_anchor..insertion_anchor, text));
12581
12582                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12583
12584                    // Move selections down
12585                    new_selections.extend(contiguous_row_selections.drain(..).map(
12586                        |mut selection| {
12587                            selection.start.row += row_delta;
12588                            selection.end.row += row_delta;
12589                            selection
12590                        },
12591                    ));
12592
12593                    // Move folds down
12594                    unfold_ranges.push(range_to_move.clone());
12595                    for fold in display_map.folds_in_range(
12596                        buffer.anchor_before(range_to_move.start)
12597                            ..buffer.anchor_after(range_to_move.end),
12598                    ) {
12599                        let mut start = fold.range.start.to_point(&buffer);
12600                        let mut end = fold.range.end.to_point(&buffer);
12601                        start.row += row_delta;
12602                        end.row += row_delta;
12603                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12604                    }
12605                }
12606            }
12607
12608            // If we didn't move line(s), preserve the existing selections
12609            new_selections.append(&mut contiguous_row_selections);
12610        }
12611
12612        self.transact(window, cx, |this, window, cx| {
12613            this.unfold_ranges(&unfold_ranges, true, true, cx);
12614            this.buffer.update(cx, |buffer, cx| {
12615                for (range, text) in edits {
12616                    buffer.edit([(range, text)], None, cx);
12617                }
12618            });
12619            this.fold_creases(refold_creases, true, window, cx);
12620            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12621        });
12622    }
12623
12624    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12625        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12626        let text_layout_details = &self.text_layout_details(window);
12627        self.transact(window, cx, |this, window, cx| {
12628            let edits = this.change_selections(Default::default(), window, cx, |s| {
12629                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12630                s.move_with(|display_map, selection| {
12631                    if !selection.is_empty() {
12632                        return;
12633                    }
12634
12635                    let mut head = selection.head();
12636                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12637                    if head.column() == display_map.line_len(head.row()) {
12638                        transpose_offset = display_map
12639                            .buffer_snapshot()
12640                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12641                    }
12642
12643                    if transpose_offset == MultiBufferOffset(0) {
12644                        return;
12645                    }
12646
12647                    *head.column_mut() += 1;
12648                    head = display_map.clip_point(head, Bias::Right);
12649                    let goal = SelectionGoal::HorizontalPosition(
12650                        display_map
12651                            .x_for_display_point(head, text_layout_details)
12652                            .into(),
12653                    );
12654                    selection.collapse_to(head, goal);
12655
12656                    let transpose_start = display_map
12657                        .buffer_snapshot()
12658                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12659                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12660                        let transpose_end = display_map
12661                            .buffer_snapshot()
12662                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12663                        if let Some(ch) = display_map
12664                            .buffer_snapshot()
12665                            .chars_at(transpose_start)
12666                            .next()
12667                        {
12668                            edits.push((transpose_start..transpose_offset, String::new()));
12669                            edits.push((transpose_end..transpose_end, ch.to_string()));
12670                        }
12671                    }
12672                });
12673                edits
12674            });
12675            this.buffer
12676                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12677            let selections = this
12678                .selections
12679                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12680            this.change_selections(Default::default(), window, cx, |s| {
12681                s.select(selections);
12682            });
12683        });
12684    }
12685
12686    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12687        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12688        if self.mode.is_single_line() {
12689            cx.propagate();
12690            return;
12691        }
12692
12693        self.rewrap_impl(RewrapOptions::default(), cx)
12694    }
12695
12696    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12697        let buffer = self.buffer.read(cx).snapshot(cx);
12698        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12699
12700        #[derive(Clone, Debug, PartialEq)]
12701        enum CommentFormat {
12702            /// single line comment, with prefix for line
12703            Line(String),
12704            /// single line within a block comment, with prefix for line
12705            BlockLine(String),
12706            /// a single line of a block comment that includes the initial delimiter
12707            BlockCommentWithStart(BlockCommentConfig),
12708            /// a single line of a block comment that includes the ending delimiter
12709            BlockCommentWithEnd(BlockCommentConfig),
12710        }
12711
12712        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12713        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12714            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12715                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12716                .peekable();
12717
12718            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12719                row
12720            } else {
12721                return Vec::new();
12722            };
12723
12724            let language_settings = buffer.language_settings_at(selection.head(), cx);
12725            let language_scope = buffer.language_scope_at(selection.head());
12726
12727            let indent_and_prefix_for_row =
12728                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12729                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12730                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12731                        &language_scope
12732                    {
12733                        let indent_end = Point::new(row, indent.len);
12734                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12735                        let line_text_after_indent = buffer
12736                            .text_for_range(indent_end..line_end)
12737                            .collect::<String>();
12738
12739                        let is_within_comment_override = buffer
12740                            .language_scope_at(indent_end)
12741                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12742                        let comment_delimiters = if is_within_comment_override {
12743                            // we are within a comment syntax node, but we don't
12744                            // yet know what kind of comment: block, doc or line
12745                            match (
12746                                language_scope.documentation_comment(),
12747                                language_scope.block_comment(),
12748                            ) {
12749                                (Some(config), _) | (_, Some(config))
12750                                    if buffer.contains_str_at(indent_end, &config.start) =>
12751                                {
12752                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12753                                }
12754                                (Some(config), _) | (_, Some(config))
12755                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12756                                {
12757                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12758                                }
12759                                (Some(config), _) | (_, Some(config))
12760                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12761                                {
12762                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12763                                }
12764                                (_, _) => language_scope
12765                                    .line_comment_prefixes()
12766                                    .iter()
12767                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12768                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12769                            }
12770                        } else {
12771                            // we not in an overridden comment node, but we may
12772                            // be within a non-overridden line comment node
12773                            language_scope
12774                                .line_comment_prefixes()
12775                                .iter()
12776                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12777                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12778                        };
12779
12780                        let rewrap_prefix = language_scope
12781                            .rewrap_prefixes()
12782                            .iter()
12783                            .find_map(|prefix_regex| {
12784                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12785                                    if mat.start() == 0 {
12786                                        Some(mat.as_str().to_string())
12787                                    } else {
12788                                        None
12789                                    }
12790                                })
12791                            })
12792                            .flatten();
12793                        (comment_delimiters, rewrap_prefix)
12794                    } else {
12795                        (None, None)
12796                    };
12797                    (indent, comment_prefix, rewrap_prefix)
12798                };
12799
12800            let mut ranges = Vec::new();
12801            let from_empty_selection = selection.is_empty();
12802
12803            let mut current_range_start = first_row;
12804            let mut prev_row = first_row;
12805            let (
12806                mut current_range_indent,
12807                mut current_range_comment_delimiters,
12808                mut current_range_rewrap_prefix,
12809            ) = indent_and_prefix_for_row(first_row);
12810
12811            for row in non_blank_rows_iter.skip(1) {
12812                let has_paragraph_break = row > prev_row + 1;
12813
12814                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12815                    indent_and_prefix_for_row(row);
12816
12817                let has_indent_change = row_indent != current_range_indent;
12818                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12819
12820                let has_boundary_change = has_comment_change
12821                    || row_rewrap_prefix.is_some()
12822                    || (has_indent_change && current_range_comment_delimiters.is_some());
12823
12824                if has_paragraph_break || has_boundary_change {
12825                    ranges.push((
12826                        language_settings.clone(),
12827                        Point::new(current_range_start, 0)
12828                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12829                        current_range_indent,
12830                        current_range_comment_delimiters.clone(),
12831                        current_range_rewrap_prefix.clone(),
12832                        from_empty_selection,
12833                    ));
12834                    current_range_start = row;
12835                    current_range_indent = row_indent;
12836                    current_range_comment_delimiters = row_comment_delimiters;
12837                    current_range_rewrap_prefix = row_rewrap_prefix;
12838                }
12839                prev_row = row;
12840            }
12841
12842            ranges.push((
12843                language_settings.clone(),
12844                Point::new(current_range_start, 0)
12845                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12846                current_range_indent,
12847                current_range_comment_delimiters,
12848                current_range_rewrap_prefix,
12849                from_empty_selection,
12850            ));
12851
12852            ranges
12853        });
12854
12855        let mut edits = Vec::new();
12856        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12857
12858        for (
12859            language_settings,
12860            wrap_range,
12861            mut indent_size,
12862            comment_prefix,
12863            rewrap_prefix,
12864            from_empty_selection,
12865        ) in wrap_ranges
12866        {
12867            let mut start_row = wrap_range.start.row;
12868            let mut end_row = wrap_range.end.row;
12869
12870            // Skip selections that overlap with a range that has already been rewrapped.
12871            let selection_range = start_row..end_row;
12872            if rewrapped_row_ranges
12873                .iter()
12874                .any(|range| range.overlaps(&selection_range))
12875            {
12876                continue;
12877            }
12878
12879            let tab_size = language_settings.tab_size;
12880
12881            let (line_prefix, inside_comment) = match &comment_prefix {
12882                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12883                    (Some(prefix.as_str()), true)
12884                }
12885                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12886                    (Some(prefix.as_ref()), true)
12887                }
12888                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12889                    start: _,
12890                    end: _,
12891                    prefix,
12892                    tab_size,
12893                })) => {
12894                    indent_size.len += tab_size;
12895                    (Some(prefix.as_ref()), true)
12896                }
12897                None => (None, false),
12898            };
12899            let indent_prefix = indent_size.chars().collect::<String>();
12900            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12901
12902            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12903                RewrapBehavior::InComments => inside_comment,
12904                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12905                RewrapBehavior::Anywhere => true,
12906            };
12907
12908            let should_rewrap = options.override_language_settings
12909                || allow_rewrap_based_on_language
12910                || self.hard_wrap.is_some();
12911            if !should_rewrap {
12912                continue;
12913            }
12914
12915            if from_empty_selection {
12916                'expand_upwards: while start_row > 0 {
12917                    let prev_row = start_row - 1;
12918                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12919                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12920                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12921                    {
12922                        start_row = prev_row;
12923                    } else {
12924                        break 'expand_upwards;
12925                    }
12926                }
12927
12928                'expand_downwards: while end_row < buffer.max_point().row {
12929                    let next_row = end_row + 1;
12930                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12931                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12932                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12933                    {
12934                        end_row = next_row;
12935                    } else {
12936                        break 'expand_downwards;
12937                    }
12938                }
12939            }
12940
12941            let start = Point::new(start_row, 0);
12942            let start_offset = ToOffset::to_offset(&start, &buffer);
12943            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12944            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12945            let mut first_line_delimiter = None;
12946            let mut last_line_delimiter = None;
12947            let Some(lines_without_prefixes) = selection_text
12948                .lines()
12949                .enumerate()
12950                .map(|(ix, line)| {
12951                    let line_trimmed = line.trim_start();
12952                    if rewrap_prefix.is_some() && ix > 0 {
12953                        Ok(line_trimmed)
12954                    } else if let Some(
12955                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12956                            start,
12957                            prefix,
12958                            end,
12959                            tab_size,
12960                        })
12961                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12962                            start,
12963                            prefix,
12964                            end,
12965                            tab_size,
12966                        }),
12967                    ) = &comment_prefix
12968                    {
12969                        let line_trimmed = line_trimmed
12970                            .strip_prefix(start.as_ref())
12971                            .map(|s| {
12972                                let mut indent_size = indent_size;
12973                                indent_size.len -= tab_size;
12974                                let indent_prefix: String = indent_size.chars().collect();
12975                                first_line_delimiter = Some((indent_prefix, start));
12976                                s.trim_start()
12977                            })
12978                            .unwrap_or(line_trimmed);
12979                        let line_trimmed = line_trimmed
12980                            .strip_suffix(end.as_ref())
12981                            .map(|s| {
12982                                last_line_delimiter = Some(end);
12983                                s.trim_end()
12984                            })
12985                            .unwrap_or(line_trimmed);
12986                        let line_trimmed = line_trimmed
12987                            .strip_prefix(prefix.as_ref())
12988                            .unwrap_or(line_trimmed);
12989                        Ok(line_trimmed)
12990                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12991                        line_trimmed.strip_prefix(prefix).with_context(|| {
12992                            format!("line did not start with prefix {prefix:?}: {line:?}")
12993                        })
12994                    } else {
12995                        line_trimmed
12996                            .strip_prefix(&line_prefix.trim_start())
12997                            .with_context(|| {
12998                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12999                            })
13000                    }
13001                })
13002                .collect::<Result<Vec<_>, _>>()
13003                .log_err()
13004            else {
13005                continue;
13006            };
13007
13008            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
13009                buffer
13010                    .language_settings_at(Point::new(start_row, 0), cx)
13011                    .preferred_line_length as usize
13012            });
13013
13014            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13015                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13016            } else {
13017                line_prefix.clone()
13018            };
13019
13020            let wrapped_text = {
13021                let mut wrapped_text = wrap_with_prefix(
13022                    line_prefix,
13023                    subsequent_lines_prefix,
13024                    lines_without_prefixes.join("\n"),
13025                    wrap_column,
13026                    tab_size,
13027                    options.preserve_existing_whitespace,
13028                );
13029
13030                if let Some((indent, delimiter)) = first_line_delimiter {
13031                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13032                }
13033                if let Some(last_line) = last_line_delimiter {
13034                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13035                }
13036
13037                wrapped_text
13038            };
13039
13040            // TODO: should always use char-based diff while still supporting cursor behavior that
13041            // matches vim.
13042            let mut diff_options = DiffOptions::default();
13043            if options.override_language_settings {
13044                diff_options.max_word_diff_len = 0;
13045                diff_options.max_word_diff_line_count = 0;
13046            } else {
13047                diff_options.max_word_diff_len = usize::MAX;
13048                diff_options.max_word_diff_line_count = usize::MAX;
13049            }
13050
13051            for (old_range, new_text) in
13052                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13053            {
13054                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13055                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13056                edits.push((edit_start..edit_end, new_text));
13057            }
13058
13059            rewrapped_row_ranges.push(start_row..=end_row);
13060        }
13061
13062        self.buffer
13063            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13064    }
13065
13066    pub fn cut_common(
13067        &mut self,
13068        cut_no_selection_line: bool,
13069        window: &mut Window,
13070        cx: &mut Context<Self>,
13071    ) -> ClipboardItem {
13072        let mut text = String::new();
13073        let buffer = self.buffer.read(cx).snapshot(cx);
13074        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13075        let mut clipboard_selections = Vec::with_capacity(selections.len());
13076        {
13077            let max_point = buffer.max_point();
13078            let mut is_first = true;
13079            let mut prev_selection_was_entire_line = false;
13080            for selection in &mut selections {
13081                let is_entire_line =
13082                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13083                if is_entire_line {
13084                    selection.start = Point::new(selection.start.row, 0);
13085                    if !selection.is_empty() && selection.end.column == 0 {
13086                        selection.end = cmp::min(max_point, selection.end);
13087                    } else {
13088                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13089                    }
13090                    selection.goal = SelectionGoal::None;
13091                }
13092                if is_first {
13093                    is_first = false;
13094                } else if !prev_selection_was_entire_line {
13095                    text += "\n";
13096                }
13097                prev_selection_was_entire_line = is_entire_line;
13098                let mut len = 0;
13099                for chunk in buffer.text_for_range(selection.start..selection.end) {
13100                    text.push_str(chunk);
13101                    len += chunk.len();
13102                }
13103
13104                clipboard_selections.push(ClipboardSelection::for_buffer(
13105                    len,
13106                    is_entire_line,
13107                    selection.range(),
13108                    &buffer,
13109                    self.project.as_ref(),
13110                    cx,
13111                ));
13112            }
13113        }
13114
13115        self.transact(window, cx, |this, window, cx| {
13116            this.change_selections(Default::default(), window, cx, |s| {
13117                s.select(selections);
13118            });
13119            this.insert("", window, cx);
13120        });
13121        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13122    }
13123
13124    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13125        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13126        let item = self.cut_common(true, window, cx);
13127        cx.write_to_clipboard(item);
13128    }
13129
13130    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13131        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13132        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13133            s.move_with(|snapshot, sel| {
13134                if sel.is_empty() {
13135                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13136                }
13137                if sel.is_empty() {
13138                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13139                }
13140            });
13141        });
13142        let item = self.cut_common(false, window, cx);
13143        cx.set_global(KillRing(item))
13144    }
13145
13146    pub fn kill_ring_yank(
13147        &mut self,
13148        _: &KillRingYank,
13149        window: &mut Window,
13150        cx: &mut Context<Self>,
13151    ) {
13152        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13153        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13154            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13155                (kill_ring.text().to_string(), kill_ring.metadata_json())
13156            } else {
13157                return;
13158            }
13159        } else {
13160            return;
13161        };
13162        self.do_paste(&text, metadata, false, window, cx);
13163    }
13164
13165    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13166        self.do_copy(true, cx);
13167    }
13168
13169    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13170        self.do_copy(false, cx);
13171    }
13172
13173    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13174        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13175        let buffer = self.buffer.read(cx).read(cx);
13176        let mut text = String::new();
13177
13178        let mut clipboard_selections = Vec::with_capacity(selections.len());
13179        {
13180            let max_point = buffer.max_point();
13181            let mut is_first = true;
13182            let mut prev_selection_was_entire_line = false;
13183            for selection in &selections {
13184                let mut start = selection.start;
13185                let mut end = selection.end;
13186                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13187                let mut add_trailing_newline = false;
13188                if is_entire_line {
13189                    start = Point::new(start.row, 0);
13190                    let next_line_start = Point::new(end.row + 1, 0);
13191                    if next_line_start <= max_point {
13192                        end = next_line_start;
13193                    } else {
13194                        // We're on the last line without a trailing newline.
13195                        // Copy to the end of the line and add a newline afterwards.
13196                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13197                        add_trailing_newline = true;
13198                    }
13199                }
13200
13201                let mut trimmed_selections = Vec::new();
13202                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13203                    let row = MultiBufferRow(start.row);
13204                    let first_indent = buffer.indent_size_for_line(row);
13205                    if first_indent.len == 0 || start.column > first_indent.len {
13206                        trimmed_selections.push(start..end);
13207                    } else {
13208                        trimmed_selections.push(
13209                            Point::new(row.0, first_indent.len)
13210                                ..Point::new(row.0, buffer.line_len(row)),
13211                        );
13212                        for row in start.row + 1..=end.row {
13213                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13214                            if row == end.row {
13215                                line_len = end.column;
13216                            }
13217                            if line_len == 0 {
13218                                trimmed_selections
13219                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13220                                continue;
13221                            }
13222                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13223                            if row_indent_size.len >= first_indent.len {
13224                                trimmed_selections.push(
13225                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13226                                );
13227                            } else {
13228                                trimmed_selections.clear();
13229                                trimmed_selections.push(start..end);
13230                                break;
13231                            }
13232                        }
13233                    }
13234                } else {
13235                    trimmed_selections.push(start..end);
13236                }
13237
13238                for trimmed_range in trimmed_selections {
13239                    if is_first {
13240                        is_first = false;
13241                    } else if !prev_selection_was_entire_line {
13242                        text += "\n";
13243                    }
13244                    prev_selection_was_entire_line = is_entire_line;
13245                    let mut len = 0;
13246                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13247                        text.push_str(chunk);
13248                        len += chunk.len();
13249                    }
13250                    if add_trailing_newline {
13251                        text.push('\n');
13252                        len += 1;
13253                    }
13254                    clipboard_selections.push(ClipboardSelection::for_buffer(
13255                        len,
13256                        is_entire_line,
13257                        trimmed_range,
13258                        &buffer,
13259                        self.project.as_ref(),
13260                        cx,
13261                    ));
13262                }
13263            }
13264        }
13265
13266        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13267            text,
13268            clipboard_selections,
13269        ));
13270    }
13271
13272    pub fn do_paste(
13273        &mut self,
13274        text: &String,
13275        clipboard_selections: Option<Vec<ClipboardSelection>>,
13276        handle_entire_lines: bool,
13277        window: &mut Window,
13278        cx: &mut Context<Self>,
13279    ) {
13280        if self.read_only(cx) {
13281            return;
13282        }
13283
13284        let clipboard_text = Cow::Borrowed(text.as_str());
13285
13286        self.transact(window, cx, |this, window, cx| {
13287            let had_active_edit_prediction = this.has_active_edit_prediction();
13288            let display_map = this.display_snapshot(cx);
13289            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13290            let cursor_offset = this
13291                .selections
13292                .last::<MultiBufferOffset>(&display_map)
13293                .head();
13294
13295            if let Some(mut clipboard_selections) = clipboard_selections {
13296                let all_selections_were_entire_line =
13297                    clipboard_selections.iter().all(|s| s.is_entire_line);
13298                let first_selection_indent_column =
13299                    clipboard_selections.first().map(|s| s.first_line_indent);
13300                if clipboard_selections.len() != old_selections.len() {
13301                    clipboard_selections.drain(..);
13302                }
13303                let mut auto_indent_on_paste = true;
13304
13305                this.buffer.update(cx, |buffer, cx| {
13306                    let snapshot = buffer.read(cx);
13307                    auto_indent_on_paste = snapshot
13308                        .language_settings_at(cursor_offset, cx)
13309                        .auto_indent_on_paste;
13310
13311                    let mut start_offset = 0;
13312                    let mut edits = Vec::new();
13313                    let mut original_indent_columns = Vec::new();
13314                    for (ix, selection) in old_selections.iter().enumerate() {
13315                        let to_insert;
13316                        let entire_line;
13317                        let original_indent_column;
13318                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13319                            let end_offset = start_offset + clipboard_selection.len;
13320                            to_insert = &clipboard_text[start_offset..end_offset];
13321                            entire_line = clipboard_selection.is_entire_line;
13322                            start_offset = if entire_line {
13323                                end_offset
13324                            } else {
13325                                end_offset + 1
13326                            };
13327                            original_indent_column = Some(clipboard_selection.first_line_indent);
13328                        } else {
13329                            to_insert = &*clipboard_text;
13330                            entire_line = all_selections_were_entire_line;
13331                            original_indent_column = first_selection_indent_column
13332                        }
13333
13334                        let (range, to_insert) =
13335                            if selection.is_empty() && handle_entire_lines && entire_line {
13336                                // If the corresponding selection was empty when this slice of the
13337                                // clipboard text was written, then the entire line containing the
13338                                // selection was copied. If this selection is also currently empty,
13339                                // then paste the line before the current line of the buffer.
13340                                let column = selection.start.to_point(&snapshot).column as usize;
13341                                let line_start = selection.start - column;
13342                                (line_start..line_start, Cow::Borrowed(to_insert))
13343                            } else {
13344                                let language = snapshot.language_at(selection.head());
13345                                let range = selection.range();
13346                                if let Some(language) = language
13347                                    && language.name() == "Markdown".into()
13348                                {
13349                                    edit_for_markdown_paste(
13350                                        &snapshot,
13351                                        range,
13352                                        to_insert,
13353                                        url::Url::parse(to_insert).ok(),
13354                                    )
13355                                } else {
13356                                    (range, Cow::Borrowed(to_insert))
13357                                }
13358                            };
13359
13360                        edits.push((range, to_insert));
13361                        original_indent_columns.push(original_indent_column);
13362                    }
13363                    drop(snapshot);
13364
13365                    buffer.edit(
13366                        edits,
13367                        if auto_indent_on_paste {
13368                            Some(AutoindentMode::Block {
13369                                original_indent_columns,
13370                            })
13371                        } else {
13372                            None
13373                        },
13374                        cx,
13375                    );
13376                });
13377
13378                let selections = this
13379                    .selections
13380                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13381                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13382            } else {
13383                let url = url::Url::parse(&clipboard_text).ok();
13384
13385                let auto_indent_mode = if !clipboard_text.is_empty() {
13386                    Some(AutoindentMode::Block {
13387                        original_indent_columns: Vec::new(),
13388                    })
13389                } else {
13390                    None
13391                };
13392
13393                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13394                    let snapshot = buffer.snapshot(cx);
13395
13396                    let anchors = old_selections
13397                        .iter()
13398                        .map(|s| {
13399                            let anchor = snapshot.anchor_after(s.head());
13400                            s.map(|_| anchor)
13401                        })
13402                        .collect::<Vec<_>>();
13403
13404                    let mut edits = Vec::new();
13405
13406                    for selection in old_selections.iter() {
13407                        let language = snapshot.language_at(selection.head());
13408                        let range = selection.range();
13409
13410                        let (edit_range, edit_text) = if let Some(language) = language
13411                            && language.name() == "Markdown".into()
13412                        {
13413                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13414                        } else {
13415                            (range, clipboard_text.clone())
13416                        };
13417
13418                        edits.push((edit_range, edit_text));
13419                    }
13420
13421                    drop(snapshot);
13422                    buffer.edit(edits, auto_indent_mode, cx);
13423
13424                    anchors
13425                });
13426
13427                this.change_selections(Default::default(), window, cx, |s| {
13428                    s.select_anchors(selection_anchors);
13429                });
13430            }
13431
13432            //   🤔                 |    ..     | show_in_menu |
13433            // | ..                  |   true        true
13434            // | had_edit_prediction |   false       true
13435
13436            let trigger_in_words =
13437                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13438
13439            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13440        });
13441    }
13442
13443    pub fn diff_clipboard_with_selection(
13444        &mut self,
13445        _: &DiffClipboardWithSelection,
13446        window: &mut Window,
13447        cx: &mut Context<Self>,
13448    ) {
13449        let selections = self
13450            .selections
13451            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13452
13453        if selections.is_empty() {
13454            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13455            return;
13456        };
13457
13458        let clipboard_text = match cx.read_from_clipboard() {
13459            Some(item) => match item.entries().first() {
13460                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13461                _ => None,
13462            },
13463            None => None,
13464        };
13465
13466        let Some(clipboard_text) = clipboard_text else {
13467            log::warn!("Clipboard doesn't contain text.");
13468            return;
13469        };
13470
13471        window.dispatch_action(
13472            Box::new(DiffClipboardWithSelectionData {
13473                clipboard_text,
13474                editor: cx.entity(),
13475            }),
13476            cx,
13477        );
13478    }
13479
13480    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13481        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13482        if let Some(item) = cx.read_from_clipboard() {
13483            let entries = item.entries();
13484
13485            match entries.first() {
13486                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13487                // of all the pasted entries.
13488                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13489                    .do_paste(
13490                        clipboard_string.text(),
13491                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13492                        true,
13493                        window,
13494                        cx,
13495                    ),
13496                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13497            }
13498        }
13499    }
13500
13501    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13502        if self.read_only(cx) {
13503            return;
13504        }
13505
13506        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13507
13508        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13509            if let Some((selections, _)) =
13510                self.selection_history.transaction(transaction_id).cloned()
13511            {
13512                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13513                    s.select_anchors(selections.to_vec());
13514                });
13515            } else {
13516                log::error!(
13517                    "No entry in selection_history found for undo. \
13518                     This may correspond to a bug where undo does not update the selection. \
13519                     If this is occurring, please add details to \
13520                     https://github.com/zed-industries/zed/issues/22692"
13521                );
13522            }
13523            self.request_autoscroll(Autoscroll::fit(), cx);
13524            self.unmark_text(window, cx);
13525            self.refresh_edit_prediction(true, false, window, cx);
13526            cx.emit(EditorEvent::Edited { transaction_id });
13527            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13528        }
13529    }
13530
13531    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13532        if self.read_only(cx) {
13533            return;
13534        }
13535
13536        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13537
13538        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13539            if let Some((_, Some(selections))) =
13540                self.selection_history.transaction(transaction_id).cloned()
13541            {
13542                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13543                    s.select_anchors(selections.to_vec());
13544                });
13545            } else {
13546                log::error!(
13547                    "No entry in selection_history found for redo. \
13548                     This may correspond to a bug where undo does not update the selection. \
13549                     If this is occurring, please add details to \
13550                     https://github.com/zed-industries/zed/issues/22692"
13551                );
13552            }
13553            self.request_autoscroll(Autoscroll::fit(), cx);
13554            self.unmark_text(window, cx);
13555            self.refresh_edit_prediction(true, false, window, cx);
13556            cx.emit(EditorEvent::Edited { transaction_id });
13557        }
13558    }
13559
13560    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13561        self.buffer
13562            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13563    }
13564
13565    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13566        self.buffer
13567            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13568    }
13569
13570    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13571        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13572        self.change_selections(Default::default(), window, cx, |s| {
13573            s.move_with(|map, selection| {
13574                let cursor = if selection.is_empty() {
13575                    movement::left(map, selection.start)
13576                } else {
13577                    selection.start
13578                };
13579                selection.collapse_to(cursor, SelectionGoal::None);
13580            });
13581        })
13582    }
13583
13584    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13585        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13586        self.change_selections(Default::default(), window, cx, |s| {
13587            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13588        })
13589    }
13590
13591    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13592        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13593        self.change_selections(Default::default(), window, cx, |s| {
13594            s.move_with(|map, selection| {
13595                let cursor = if selection.is_empty() {
13596                    movement::right(map, selection.end)
13597                } else {
13598                    selection.end
13599                };
13600                selection.collapse_to(cursor, SelectionGoal::None)
13601            });
13602        })
13603    }
13604
13605    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13606        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13607        self.change_selections(Default::default(), window, cx, |s| {
13608            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13609        });
13610    }
13611
13612    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13613        if self.take_rename(true, window, cx).is_some() {
13614            return;
13615        }
13616
13617        if self.mode.is_single_line() {
13618            cx.propagate();
13619            return;
13620        }
13621
13622        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13623
13624        let text_layout_details = &self.text_layout_details(window);
13625        let selection_count = self.selections.count();
13626        let first_selection = self.selections.first_anchor();
13627
13628        self.change_selections(Default::default(), window, cx, |s| {
13629            s.move_with(|map, selection| {
13630                if !selection.is_empty() {
13631                    selection.goal = SelectionGoal::None;
13632                }
13633                let (cursor, goal) = movement::up(
13634                    map,
13635                    selection.start,
13636                    selection.goal,
13637                    false,
13638                    text_layout_details,
13639                );
13640                selection.collapse_to(cursor, goal);
13641            });
13642        });
13643
13644        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13645        {
13646            cx.propagate();
13647        }
13648    }
13649
13650    pub fn move_up_by_lines(
13651        &mut self,
13652        action: &MoveUpByLines,
13653        window: &mut Window,
13654        cx: &mut Context<Self>,
13655    ) {
13656        if self.take_rename(true, window, cx).is_some() {
13657            return;
13658        }
13659
13660        if self.mode.is_single_line() {
13661            cx.propagate();
13662            return;
13663        }
13664
13665        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13666
13667        let text_layout_details = &self.text_layout_details(window);
13668
13669        self.change_selections(Default::default(), window, cx, |s| {
13670            s.move_with(|map, selection| {
13671                if !selection.is_empty() {
13672                    selection.goal = SelectionGoal::None;
13673                }
13674                let (cursor, goal) = movement::up_by_rows(
13675                    map,
13676                    selection.start,
13677                    action.lines,
13678                    selection.goal,
13679                    false,
13680                    text_layout_details,
13681                );
13682                selection.collapse_to(cursor, goal);
13683            });
13684        })
13685    }
13686
13687    pub fn move_down_by_lines(
13688        &mut self,
13689        action: &MoveDownByLines,
13690        window: &mut Window,
13691        cx: &mut Context<Self>,
13692    ) {
13693        if self.take_rename(true, window, cx).is_some() {
13694            return;
13695        }
13696
13697        if self.mode.is_single_line() {
13698            cx.propagate();
13699            return;
13700        }
13701
13702        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13703
13704        let text_layout_details = &self.text_layout_details(window);
13705
13706        self.change_selections(Default::default(), window, cx, |s| {
13707            s.move_with(|map, selection| {
13708                if !selection.is_empty() {
13709                    selection.goal = SelectionGoal::None;
13710                }
13711                let (cursor, goal) = movement::down_by_rows(
13712                    map,
13713                    selection.start,
13714                    action.lines,
13715                    selection.goal,
13716                    false,
13717                    text_layout_details,
13718                );
13719                selection.collapse_to(cursor, goal);
13720            });
13721        })
13722    }
13723
13724    pub fn select_down_by_lines(
13725        &mut self,
13726        action: &SelectDownByLines,
13727        window: &mut Window,
13728        cx: &mut Context<Self>,
13729    ) {
13730        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13731        let text_layout_details = &self.text_layout_details(window);
13732        self.change_selections(Default::default(), window, cx, |s| {
13733            s.move_heads_with(|map, head, goal| {
13734                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13735            })
13736        })
13737    }
13738
13739    pub fn select_up_by_lines(
13740        &mut self,
13741        action: &SelectUpByLines,
13742        window: &mut Window,
13743        cx: &mut Context<Self>,
13744    ) {
13745        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13746        let text_layout_details = &self.text_layout_details(window);
13747        self.change_selections(Default::default(), window, cx, |s| {
13748            s.move_heads_with(|map, head, goal| {
13749                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13750            })
13751        })
13752    }
13753
13754    pub fn select_page_up(
13755        &mut self,
13756        _: &SelectPageUp,
13757        window: &mut Window,
13758        cx: &mut Context<Self>,
13759    ) {
13760        let Some(row_count) = self.visible_row_count() else {
13761            return;
13762        };
13763
13764        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13765
13766        let text_layout_details = &self.text_layout_details(window);
13767
13768        self.change_selections(Default::default(), window, cx, |s| {
13769            s.move_heads_with(|map, head, goal| {
13770                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13771            })
13772        })
13773    }
13774
13775    pub fn move_page_up(
13776        &mut self,
13777        action: &MovePageUp,
13778        window: &mut Window,
13779        cx: &mut Context<Self>,
13780    ) {
13781        if self.take_rename(true, window, cx).is_some() {
13782            return;
13783        }
13784
13785        if self
13786            .context_menu
13787            .borrow_mut()
13788            .as_mut()
13789            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13790            .unwrap_or(false)
13791        {
13792            return;
13793        }
13794
13795        if matches!(self.mode, EditorMode::SingleLine) {
13796            cx.propagate();
13797            return;
13798        }
13799
13800        let Some(row_count) = self.visible_row_count() else {
13801            return;
13802        };
13803
13804        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13805
13806        let effects = if action.center_cursor {
13807            SelectionEffects::scroll(Autoscroll::center())
13808        } else {
13809            SelectionEffects::default()
13810        };
13811
13812        let text_layout_details = &self.text_layout_details(window);
13813
13814        self.change_selections(effects, window, cx, |s| {
13815            s.move_with(|map, selection| {
13816                if !selection.is_empty() {
13817                    selection.goal = SelectionGoal::None;
13818                }
13819                let (cursor, goal) = movement::up_by_rows(
13820                    map,
13821                    selection.end,
13822                    row_count,
13823                    selection.goal,
13824                    false,
13825                    text_layout_details,
13826                );
13827                selection.collapse_to(cursor, goal);
13828            });
13829        });
13830    }
13831
13832    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13833        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13834        let text_layout_details = &self.text_layout_details(window);
13835        self.change_selections(Default::default(), window, cx, |s| {
13836            s.move_heads_with(|map, head, goal| {
13837                movement::up(map, head, goal, false, text_layout_details)
13838            })
13839        })
13840    }
13841
13842    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13843        self.take_rename(true, window, cx);
13844
13845        if self.mode.is_single_line() {
13846            cx.propagate();
13847            return;
13848        }
13849
13850        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13851
13852        let text_layout_details = &self.text_layout_details(window);
13853        let selection_count = self.selections.count();
13854        let first_selection = self.selections.first_anchor();
13855
13856        self.change_selections(Default::default(), window, cx, |s| {
13857            s.move_with(|map, selection| {
13858                if !selection.is_empty() {
13859                    selection.goal = SelectionGoal::None;
13860                }
13861                let (cursor, goal) = movement::down(
13862                    map,
13863                    selection.end,
13864                    selection.goal,
13865                    false,
13866                    text_layout_details,
13867                );
13868                selection.collapse_to(cursor, goal);
13869            });
13870        });
13871
13872        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13873        {
13874            cx.propagate();
13875        }
13876    }
13877
13878    pub fn select_page_down(
13879        &mut self,
13880        _: &SelectPageDown,
13881        window: &mut Window,
13882        cx: &mut Context<Self>,
13883    ) {
13884        let Some(row_count) = self.visible_row_count() else {
13885            return;
13886        };
13887
13888        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13889
13890        let text_layout_details = &self.text_layout_details(window);
13891
13892        self.change_selections(Default::default(), window, cx, |s| {
13893            s.move_heads_with(|map, head, goal| {
13894                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13895            })
13896        })
13897    }
13898
13899    pub fn move_page_down(
13900        &mut self,
13901        action: &MovePageDown,
13902        window: &mut Window,
13903        cx: &mut Context<Self>,
13904    ) {
13905        if self.take_rename(true, window, cx).is_some() {
13906            return;
13907        }
13908
13909        if self
13910            .context_menu
13911            .borrow_mut()
13912            .as_mut()
13913            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13914            .unwrap_or(false)
13915        {
13916            return;
13917        }
13918
13919        if matches!(self.mode, EditorMode::SingleLine) {
13920            cx.propagate();
13921            return;
13922        }
13923
13924        let Some(row_count) = self.visible_row_count() else {
13925            return;
13926        };
13927
13928        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13929
13930        let effects = if action.center_cursor {
13931            SelectionEffects::scroll(Autoscroll::center())
13932        } else {
13933            SelectionEffects::default()
13934        };
13935
13936        let text_layout_details = &self.text_layout_details(window);
13937        self.change_selections(effects, window, cx, |s| {
13938            s.move_with(|map, selection| {
13939                if !selection.is_empty() {
13940                    selection.goal = SelectionGoal::None;
13941                }
13942                let (cursor, goal) = movement::down_by_rows(
13943                    map,
13944                    selection.end,
13945                    row_count,
13946                    selection.goal,
13947                    false,
13948                    text_layout_details,
13949                );
13950                selection.collapse_to(cursor, goal);
13951            });
13952        });
13953    }
13954
13955    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13956        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13957        let text_layout_details = &self.text_layout_details(window);
13958        self.change_selections(Default::default(), window, cx, |s| {
13959            s.move_heads_with(|map, head, goal| {
13960                movement::down(map, head, goal, false, text_layout_details)
13961            })
13962        });
13963    }
13964
13965    pub fn context_menu_first(
13966        &mut self,
13967        _: &ContextMenuFirst,
13968        window: &mut Window,
13969        cx: &mut Context<Self>,
13970    ) {
13971        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13972            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13973        }
13974    }
13975
13976    pub fn context_menu_prev(
13977        &mut self,
13978        _: &ContextMenuPrevious,
13979        window: &mut Window,
13980        cx: &mut Context<Self>,
13981    ) {
13982        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13983            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13984        }
13985    }
13986
13987    pub fn context_menu_next(
13988        &mut self,
13989        _: &ContextMenuNext,
13990        window: &mut Window,
13991        cx: &mut Context<Self>,
13992    ) {
13993        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13994            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13995        }
13996    }
13997
13998    pub fn context_menu_last(
13999        &mut self,
14000        _: &ContextMenuLast,
14001        window: &mut Window,
14002        cx: &mut Context<Self>,
14003    ) {
14004        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14005            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14006        }
14007    }
14008
14009    pub fn signature_help_prev(
14010        &mut self,
14011        _: &SignatureHelpPrevious,
14012        _: &mut Window,
14013        cx: &mut Context<Self>,
14014    ) {
14015        if let Some(popover) = self.signature_help_state.popover_mut() {
14016            if popover.current_signature == 0 {
14017                popover.current_signature = popover.signatures.len() - 1;
14018            } else {
14019                popover.current_signature -= 1;
14020            }
14021            cx.notify();
14022        }
14023    }
14024
14025    pub fn signature_help_next(
14026        &mut self,
14027        _: &SignatureHelpNext,
14028        _: &mut Window,
14029        cx: &mut Context<Self>,
14030    ) {
14031        if let Some(popover) = self.signature_help_state.popover_mut() {
14032            if popover.current_signature + 1 == popover.signatures.len() {
14033                popover.current_signature = 0;
14034            } else {
14035                popover.current_signature += 1;
14036            }
14037            cx.notify();
14038        }
14039    }
14040
14041    pub fn move_to_previous_word_start(
14042        &mut self,
14043        _: &MoveToPreviousWordStart,
14044        window: &mut Window,
14045        cx: &mut Context<Self>,
14046    ) {
14047        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14048        self.change_selections(Default::default(), window, cx, |s| {
14049            s.move_cursors_with(|map, head, _| {
14050                (
14051                    movement::previous_word_start(map, head),
14052                    SelectionGoal::None,
14053                )
14054            });
14055        })
14056    }
14057
14058    pub fn move_to_previous_subword_start(
14059        &mut self,
14060        _: &MoveToPreviousSubwordStart,
14061        window: &mut Window,
14062        cx: &mut Context<Self>,
14063    ) {
14064        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14065        self.change_selections(Default::default(), window, cx, |s| {
14066            s.move_cursors_with(|map, head, _| {
14067                (
14068                    movement::previous_subword_start(map, head),
14069                    SelectionGoal::None,
14070                )
14071            });
14072        })
14073    }
14074
14075    pub fn select_to_previous_word_start(
14076        &mut self,
14077        _: &SelectToPreviousWordStart,
14078        window: &mut Window,
14079        cx: &mut Context<Self>,
14080    ) {
14081        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14082        self.change_selections(Default::default(), window, cx, |s| {
14083            s.move_heads_with(|map, head, _| {
14084                (
14085                    movement::previous_word_start(map, head),
14086                    SelectionGoal::None,
14087                )
14088            });
14089        })
14090    }
14091
14092    pub fn select_to_previous_subword_start(
14093        &mut self,
14094        _: &SelectToPreviousSubwordStart,
14095        window: &mut Window,
14096        cx: &mut Context<Self>,
14097    ) {
14098        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14099        self.change_selections(Default::default(), window, cx, |s| {
14100            s.move_heads_with(|map, head, _| {
14101                (
14102                    movement::previous_subword_start(map, head),
14103                    SelectionGoal::None,
14104                )
14105            });
14106        })
14107    }
14108
14109    pub fn delete_to_previous_word_start(
14110        &mut self,
14111        action: &DeleteToPreviousWordStart,
14112        window: &mut Window,
14113        cx: &mut Context<Self>,
14114    ) {
14115        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14116        self.transact(window, cx, |this, window, cx| {
14117            this.select_autoclose_pair(window, cx);
14118            this.change_selections(Default::default(), window, cx, |s| {
14119                s.move_with(|map, selection| {
14120                    if selection.is_empty() {
14121                        let mut cursor = if action.ignore_newlines {
14122                            movement::previous_word_start(map, selection.head())
14123                        } else {
14124                            movement::previous_word_start_or_newline(map, selection.head())
14125                        };
14126                        cursor = movement::adjust_greedy_deletion(
14127                            map,
14128                            selection.head(),
14129                            cursor,
14130                            action.ignore_brackets,
14131                        );
14132                        selection.set_head(cursor, SelectionGoal::None);
14133                    }
14134                });
14135            });
14136            this.insert("", window, cx);
14137        });
14138    }
14139
14140    pub fn delete_to_previous_subword_start(
14141        &mut self,
14142        _: &DeleteToPreviousSubwordStart,
14143        window: &mut Window,
14144        cx: &mut Context<Self>,
14145    ) {
14146        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14147        self.transact(window, cx, |this, window, cx| {
14148            this.select_autoclose_pair(window, cx);
14149            this.change_selections(Default::default(), window, cx, |s| {
14150                s.move_with(|map, selection| {
14151                    if selection.is_empty() {
14152                        let mut cursor = movement::previous_subword_start(map, selection.head());
14153                        cursor =
14154                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14155                        selection.set_head(cursor, SelectionGoal::None);
14156                    }
14157                });
14158            });
14159            this.insert("", window, cx);
14160        });
14161    }
14162
14163    pub fn move_to_next_word_end(
14164        &mut self,
14165        _: &MoveToNextWordEnd,
14166        window: &mut Window,
14167        cx: &mut Context<Self>,
14168    ) {
14169        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14170        self.change_selections(Default::default(), window, cx, |s| {
14171            s.move_cursors_with(|map, head, _| {
14172                (movement::next_word_end(map, head), SelectionGoal::None)
14173            });
14174        })
14175    }
14176
14177    pub fn move_to_next_subword_end(
14178        &mut self,
14179        _: &MoveToNextSubwordEnd,
14180        window: &mut Window,
14181        cx: &mut Context<Self>,
14182    ) {
14183        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14184        self.change_selections(Default::default(), window, cx, |s| {
14185            s.move_cursors_with(|map, head, _| {
14186                (movement::next_subword_end(map, head), SelectionGoal::None)
14187            });
14188        })
14189    }
14190
14191    pub fn select_to_next_word_end(
14192        &mut self,
14193        _: &SelectToNextWordEnd,
14194        window: &mut Window,
14195        cx: &mut Context<Self>,
14196    ) {
14197        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14198        self.change_selections(Default::default(), window, cx, |s| {
14199            s.move_heads_with(|map, head, _| {
14200                (movement::next_word_end(map, head), SelectionGoal::None)
14201            });
14202        })
14203    }
14204
14205    pub fn select_to_next_subword_end(
14206        &mut self,
14207        _: &SelectToNextSubwordEnd,
14208        window: &mut Window,
14209        cx: &mut Context<Self>,
14210    ) {
14211        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14212        self.change_selections(Default::default(), window, cx, |s| {
14213            s.move_heads_with(|map, head, _| {
14214                (movement::next_subword_end(map, head), SelectionGoal::None)
14215            });
14216        })
14217    }
14218
14219    pub fn delete_to_next_word_end(
14220        &mut self,
14221        action: &DeleteToNextWordEnd,
14222        window: &mut Window,
14223        cx: &mut Context<Self>,
14224    ) {
14225        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14226        self.transact(window, cx, |this, window, cx| {
14227            this.change_selections(Default::default(), window, cx, |s| {
14228                s.move_with(|map, selection| {
14229                    if selection.is_empty() {
14230                        let mut cursor = if action.ignore_newlines {
14231                            movement::next_word_end(map, selection.head())
14232                        } else {
14233                            movement::next_word_end_or_newline(map, selection.head())
14234                        };
14235                        cursor = movement::adjust_greedy_deletion(
14236                            map,
14237                            selection.head(),
14238                            cursor,
14239                            action.ignore_brackets,
14240                        );
14241                        selection.set_head(cursor, SelectionGoal::None);
14242                    }
14243                });
14244            });
14245            this.insert("", window, cx);
14246        });
14247    }
14248
14249    pub fn delete_to_next_subword_end(
14250        &mut self,
14251        _: &DeleteToNextSubwordEnd,
14252        window: &mut Window,
14253        cx: &mut Context<Self>,
14254    ) {
14255        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14256        self.transact(window, cx, |this, window, cx| {
14257            this.change_selections(Default::default(), window, cx, |s| {
14258                s.move_with(|map, selection| {
14259                    if selection.is_empty() {
14260                        let mut cursor = movement::next_subword_end(map, selection.head());
14261                        cursor =
14262                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14263                        selection.set_head(cursor, SelectionGoal::None);
14264                    }
14265                });
14266            });
14267            this.insert("", window, cx);
14268        });
14269    }
14270
14271    pub fn move_to_beginning_of_line(
14272        &mut self,
14273        action: &MoveToBeginningOfLine,
14274        window: &mut Window,
14275        cx: &mut Context<Self>,
14276    ) {
14277        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14278        self.change_selections(Default::default(), window, cx, |s| {
14279            s.move_cursors_with(|map, head, _| {
14280                (
14281                    movement::indented_line_beginning(
14282                        map,
14283                        head,
14284                        action.stop_at_soft_wraps,
14285                        action.stop_at_indent,
14286                    ),
14287                    SelectionGoal::None,
14288                )
14289            });
14290        })
14291    }
14292
14293    pub fn select_to_beginning_of_line(
14294        &mut self,
14295        action: &SelectToBeginningOfLine,
14296        window: &mut Window,
14297        cx: &mut Context<Self>,
14298    ) {
14299        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14300        self.change_selections(Default::default(), window, cx, |s| {
14301            s.move_heads_with(|map, head, _| {
14302                (
14303                    movement::indented_line_beginning(
14304                        map,
14305                        head,
14306                        action.stop_at_soft_wraps,
14307                        action.stop_at_indent,
14308                    ),
14309                    SelectionGoal::None,
14310                )
14311            });
14312        });
14313    }
14314
14315    pub fn delete_to_beginning_of_line(
14316        &mut self,
14317        action: &DeleteToBeginningOfLine,
14318        window: &mut Window,
14319        cx: &mut Context<Self>,
14320    ) {
14321        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14322        self.transact(window, cx, |this, window, cx| {
14323            this.change_selections(Default::default(), window, cx, |s| {
14324                s.move_with(|_, selection| {
14325                    selection.reversed = true;
14326                });
14327            });
14328
14329            this.select_to_beginning_of_line(
14330                &SelectToBeginningOfLine {
14331                    stop_at_soft_wraps: false,
14332                    stop_at_indent: action.stop_at_indent,
14333                },
14334                window,
14335                cx,
14336            );
14337            this.backspace(&Backspace, window, cx);
14338        });
14339    }
14340
14341    pub fn move_to_end_of_line(
14342        &mut self,
14343        action: &MoveToEndOfLine,
14344        window: &mut Window,
14345        cx: &mut Context<Self>,
14346    ) {
14347        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14348        self.change_selections(Default::default(), window, cx, |s| {
14349            s.move_cursors_with(|map, head, _| {
14350                (
14351                    movement::line_end(map, head, action.stop_at_soft_wraps),
14352                    SelectionGoal::None,
14353                )
14354            });
14355        })
14356    }
14357
14358    pub fn select_to_end_of_line(
14359        &mut self,
14360        action: &SelectToEndOfLine,
14361        window: &mut Window,
14362        cx: &mut Context<Self>,
14363    ) {
14364        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14365        self.change_selections(Default::default(), window, cx, |s| {
14366            s.move_heads_with(|map, head, _| {
14367                (
14368                    movement::line_end(map, head, action.stop_at_soft_wraps),
14369                    SelectionGoal::None,
14370                )
14371            });
14372        })
14373    }
14374
14375    pub fn delete_to_end_of_line(
14376        &mut self,
14377        _: &DeleteToEndOfLine,
14378        window: &mut Window,
14379        cx: &mut Context<Self>,
14380    ) {
14381        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14382        self.transact(window, cx, |this, window, cx| {
14383            this.select_to_end_of_line(
14384                &SelectToEndOfLine {
14385                    stop_at_soft_wraps: false,
14386                },
14387                window,
14388                cx,
14389            );
14390            this.delete(&Delete, window, cx);
14391        });
14392    }
14393
14394    pub fn cut_to_end_of_line(
14395        &mut self,
14396        action: &CutToEndOfLine,
14397        window: &mut Window,
14398        cx: &mut Context<Self>,
14399    ) {
14400        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14401        self.transact(window, cx, |this, window, cx| {
14402            this.select_to_end_of_line(
14403                &SelectToEndOfLine {
14404                    stop_at_soft_wraps: false,
14405                },
14406                window,
14407                cx,
14408            );
14409            if !action.stop_at_newlines {
14410                this.change_selections(Default::default(), window, cx, |s| {
14411                    s.move_with(|_, sel| {
14412                        if sel.is_empty() {
14413                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14414                        }
14415                    });
14416                });
14417            }
14418            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14419            let item = this.cut_common(false, window, cx);
14420            cx.write_to_clipboard(item);
14421        });
14422    }
14423
14424    pub fn move_to_start_of_paragraph(
14425        &mut self,
14426        _: &MoveToStartOfParagraph,
14427        window: &mut Window,
14428        cx: &mut Context<Self>,
14429    ) {
14430        if matches!(self.mode, EditorMode::SingleLine) {
14431            cx.propagate();
14432            return;
14433        }
14434        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14435        self.change_selections(Default::default(), window, cx, |s| {
14436            s.move_with(|map, selection| {
14437                selection.collapse_to(
14438                    movement::start_of_paragraph(map, selection.head(), 1),
14439                    SelectionGoal::None,
14440                )
14441            });
14442        })
14443    }
14444
14445    pub fn move_to_end_of_paragraph(
14446        &mut self,
14447        _: &MoveToEndOfParagraph,
14448        window: &mut Window,
14449        cx: &mut Context<Self>,
14450    ) {
14451        if matches!(self.mode, EditorMode::SingleLine) {
14452            cx.propagate();
14453            return;
14454        }
14455        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14456        self.change_selections(Default::default(), window, cx, |s| {
14457            s.move_with(|map, selection| {
14458                selection.collapse_to(
14459                    movement::end_of_paragraph(map, selection.head(), 1),
14460                    SelectionGoal::None,
14461                )
14462            });
14463        })
14464    }
14465
14466    pub fn select_to_start_of_paragraph(
14467        &mut self,
14468        _: &SelectToStartOfParagraph,
14469        window: &mut Window,
14470        cx: &mut Context<Self>,
14471    ) {
14472        if matches!(self.mode, EditorMode::SingleLine) {
14473            cx.propagate();
14474            return;
14475        }
14476        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14477        self.change_selections(Default::default(), window, cx, |s| {
14478            s.move_heads_with(|map, head, _| {
14479                (
14480                    movement::start_of_paragraph(map, head, 1),
14481                    SelectionGoal::None,
14482                )
14483            });
14484        })
14485    }
14486
14487    pub fn select_to_end_of_paragraph(
14488        &mut self,
14489        _: &SelectToEndOfParagraph,
14490        window: &mut Window,
14491        cx: &mut Context<Self>,
14492    ) {
14493        if matches!(self.mode, EditorMode::SingleLine) {
14494            cx.propagate();
14495            return;
14496        }
14497        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14498        self.change_selections(Default::default(), window, cx, |s| {
14499            s.move_heads_with(|map, head, _| {
14500                (
14501                    movement::end_of_paragraph(map, head, 1),
14502                    SelectionGoal::None,
14503                )
14504            });
14505        })
14506    }
14507
14508    pub fn move_to_start_of_excerpt(
14509        &mut self,
14510        _: &MoveToStartOfExcerpt,
14511        window: &mut Window,
14512        cx: &mut Context<Self>,
14513    ) {
14514        if matches!(self.mode, EditorMode::SingleLine) {
14515            cx.propagate();
14516            return;
14517        }
14518        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14519        self.change_selections(Default::default(), window, cx, |s| {
14520            s.move_with(|map, selection| {
14521                selection.collapse_to(
14522                    movement::start_of_excerpt(
14523                        map,
14524                        selection.head(),
14525                        workspace::searchable::Direction::Prev,
14526                    ),
14527                    SelectionGoal::None,
14528                )
14529            });
14530        })
14531    }
14532
14533    pub fn move_to_start_of_next_excerpt(
14534        &mut self,
14535        _: &MoveToStartOfNextExcerpt,
14536        window: &mut Window,
14537        cx: &mut Context<Self>,
14538    ) {
14539        if matches!(self.mode, EditorMode::SingleLine) {
14540            cx.propagate();
14541            return;
14542        }
14543
14544        self.change_selections(Default::default(), window, cx, |s| {
14545            s.move_with(|map, selection| {
14546                selection.collapse_to(
14547                    movement::start_of_excerpt(
14548                        map,
14549                        selection.head(),
14550                        workspace::searchable::Direction::Next,
14551                    ),
14552                    SelectionGoal::None,
14553                )
14554            });
14555        })
14556    }
14557
14558    pub fn move_to_end_of_excerpt(
14559        &mut self,
14560        _: &MoveToEndOfExcerpt,
14561        window: &mut Window,
14562        cx: &mut Context<Self>,
14563    ) {
14564        if matches!(self.mode, EditorMode::SingleLine) {
14565            cx.propagate();
14566            return;
14567        }
14568        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14569        self.change_selections(Default::default(), window, cx, |s| {
14570            s.move_with(|map, selection| {
14571                selection.collapse_to(
14572                    movement::end_of_excerpt(
14573                        map,
14574                        selection.head(),
14575                        workspace::searchable::Direction::Next,
14576                    ),
14577                    SelectionGoal::None,
14578                )
14579            });
14580        })
14581    }
14582
14583    pub fn move_to_end_of_previous_excerpt(
14584        &mut self,
14585        _: &MoveToEndOfPreviousExcerpt,
14586        window: &mut Window,
14587        cx: &mut Context<Self>,
14588    ) {
14589        if matches!(self.mode, EditorMode::SingleLine) {
14590            cx.propagate();
14591            return;
14592        }
14593        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14594        self.change_selections(Default::default(), window, cx, |s| {
14595            s.move_with(|map, selection| {
14596                selection.collapse_to(
14597                    movement::end_of_excerpt(
14598                        map,
14599                        selection.head(),
14600                        workspace::searchable::Direction::Prev,
14601                    ),
14602                    SelectionGoal::None,
14603                )
14604            });
14605        })
14606    }
14607
14608    pub fn select_to_start_of_excerpt(
14609        &mut self,
14610        _: &SelectToStartOfExcerpt,
14611        window: &mut Window,
14612        cx: &mut Context<Self>,
14613    ) {
14614        if matches!(self.mode, EditorMode::SingleLine) {
14615            cx.propagate();
14616            return;
14617        }
14618        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14619        self.change_selections(Default::default(), window, cx, |s| {
14620            s.move_heads_with(|map, head, _| {
14621                (
14622                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14623                    SelectionGoal::None,
14624                )
14625            });
14626        })
14627    }
14628
14629    pub fn select_to_start_of_next_excerpt(
14630        &mut self,
14631        _: &SelectToStartOfNextExcerpt,
14632        window: &mut Window,
14633        cx: &mut Context<Self>,
14634    ) {
14635        if matches!(self.mode, EditorMode::SingleLine) {
14636            cx.propagate();
14637            return;
14638        }
14639        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14640        self.change_selections(Default::default(), window, cx, |s| {
14641            s.move_heads_with(|map, head, _| {
14642                (
14643                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14644                    SelectionGoal::None,
14645                )
14646            });
14647        })
14648    }
14649
14650    pub fn select_to_end_of_excerpt(
14651        &mut self,
14652        _: &SelectToEndOfExcerpt,
14653        window: &mut Window,
14654        cx: &mut Context<Self>,
14655    ) {
14656        if matches!(self.mode, EditorMode::SingleLine) {
14657            cx.propagate();
14658            return;
14659        }
14660        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14661        self.change_selections(Default::default(), window, cx, |s| {
14662            s.move_heads_with(|map, head, _| {
14663                (
14664                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14665                    SelectionGoal::None,
14666                )
14667            });
14668        })
14669    }
14670
14671    pub fn select_to_end_of_previous_excerpt(
14672        &mut self,
14673        _: &SelectToEndOfPreviousExcerpt,
14674        window: &mut Window,
14675        cx: &mut Context<Self>,
14676    ) {
14677        if matches!(self.mode, EditorMode::SingleLine) {
14678            cx.propagate();
14679            return;
14680        }
14681        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14682        self.change_selections(Default::default(), window, cx, |s| {
14683            s.move_heads_with(|map, head, _| {
14684                (
14685                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14686                    SelectionGoal::None,
14687                )
14688            });
14689        })
14690    }
14691
14692    pub fn move_to_beginning(
14693        &mut self,
14694        _: &MoveToBeginning,
14695        window: &mut Window,
14696        cx: &mut Context<Self>,
14697    ) {
14698        if matches!(self.mode, EditorMode::SingleLine) {
14699            cx.propagate();
14700            return;
14701        }
14702        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14703        self.change_selections(Default::default(), window, cx, |s| {
14704            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14705        });
14706    }
14707
14708    pub fn select_to_beginning(
14709        &mut self,
14710        _: &SelectToBeginning,
14711        window: &mut Window,
14712        cx: &mut Context<Self>,
14713    ) {
14714        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14715        selection.set_head(Point::zero(), SelectionGoal::None);
14716        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14717        self.change_selections(Default::default(), window, cx, |s| {
14718            s.select(vec![selection]);
14719        });
14720    }
14721
14722    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14723        if matches!(self.mode, EditorMode::SingleLine) {
14724            cx.propagate();
14725            return;
14726        }
14727        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14728        let cursor = self.buffer.read(cx).read(cx).len();
14729        self.change_selections(Default::default(), window, cx, |s| {
14730            s.select_ranges(vec![cursor..cursor])
14731        });
14732    }
14733
14734    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14735        self.nav_history = nav_history;
14736    }
14737
14738    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14739        self.nav_history.as_ref()
14740    }
14741
14742    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14743        self.push_to_nav_history(
14744            self.selections.newest_anchor().head(),
14745            None,
14746            false,
14747            true,
14748            cx,
14749        );
14750    }
14751
14752    fn push_to_nav_history(
14753        &mut self,
14754        cursor_anchor: Anchor,
14755        new_position: Option<Point>,
14756        is_deactivate: bool,
14757        always: bool,
14758        cx: &mut Context<Self>,
14759    ) {
14760        if let Some(nav_history) = self.nav_history.as_mut() {
14761            let buffer = self.buffer.read(cx).read(cx);
14762            let cursor_position = cursor_anchor.to_point(&buffer);
14763            let scroll_state = self.scroll_manager.anchor();
14764            let scroll_top_row = scroll_state.top_row(&buffer);
14765            drop(buffer);
14766
14767            if let Some(new_position) = new_position {
14768                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14769                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14770                    return;
14771                }
14772            }
14773
14774            nav_history.push(
14775                Some(NavigationData {
14776                    cursor_anchor,
14777                    cursor_position,
14778                    scroll_anchor: scroll_state,
14779                    scroll_top_row,
14780                }),
14781                cx,
14782            );
14783            cx.emit(EditorEvent::PushedToNavHistory {
14784                anchor: cursor_anchor,
14785                is_deactivate,
14786            })
14787        }
14788    }
14789
14790    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14791        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14792        let buffer = self.buffer.read(cx).snapshot(cx);
14793        let mut selection = self
14794            .selections
14795            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14796        selection.set_head(buffer.len(), SelectionGoal::None);
14797        self.change_selections(Default::default(), window, cx, |s| {
14798            s.select(vec![selection]);
14799        });
14800    }
14801
14802    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14803        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14804        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14805            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14806        });
14807    }
14808
14809    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14810        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14811        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14812        let mut selections = self.selections.all::<Point>(&display_map);
14813        let max_point = display_map.buffer_snapshot().max_point();
14814        for selection in &mut selections {
14815            let rows = selection.spanned_rows(true, &display_map);
14816            selection.start = Point::new(rows.start.0, 0);
14817            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14818            selection.reversed = false;
14819        }
14820        self.change_selections(Default::default(), window, cx, |s| {
14821            s.select(selections);
14822        });
14823    }
14824
14825    pub fn split_selection_into_lines(
14826        &mut self,
14827        action: &SplitSelectionIntoLines,
14828        window: &mut Window,
14829        cx: &mut Context<Self>,
14830    ) {
14831        let selections = self
14832            .selections
14833            .all::<Point>(&self.display_snapshot(cx))
14834            .into_iter()
14835            .map(|selection| selection.start..selection.end)
14836            .collect::<Vec<_>>();
14837        self.unfold_ranges(&selections, true, true, cx);
14838
14839        let mut new_selection_ranges = Vec::new();
14840        {
14841            let buffer = self.buffer.read(cx).read(cx);
14842            for selection in selections {
14843                for row in selection.start.row..selection.end.row {
14844                    let line_start = Point::new(row, 0);
14845                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14846
14847                    if action.keep_selections {
14848                        // Keep the selection range for each line
14849                        let selection_start = if row == selection.start.row {
14850                            selection.start
14851                        } else {
14852                            line_start
14853                        };
14854                        new_selection_ranges.push(selection_start..line_end);
14855                    } else {
14856                        // Collapse to cursor at end of line
14857                        new_selection_ranges.push(line_end..line_end);
14858                    }
14859                }
14860
14861                let is_multiline_selection = selection.start.row != selection.end.row;
14862                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14863                // so this action feels more ergonomic when paired with other selection operations
14864                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14865                if !should_skip_last {
14866                    if action.keep_selections {
14867                        if is_multiline_selection {
14868                            let line_start = Point::new(selection.end.row, 0);
14869                            new_selection_ranges.push(line_start..selection.end);
14870                        } else {
14871                            new_selection_ranges.push(selection.start..selection.end);
14872                        }
14873                    } else {
14874                        new_selection_ranges.push(selection.end..selection.end);
14875                    }
14876                }
14877            }
14878        }
14879        self.change_selections(Default::default(), window, cx, |s| {
14880            s.select_ranges(new_selection_ranges);
14881        });
14882    }
14883
14884    pub fn add_selection_above(
14885        &mut self,
14886        action: &AddSelectionAbove,
14887        window: &mut Window,
14888        cx: &mut Context<Self>,
14889    ) {
14890        self.add_selection(true, action.skip_soft_wrap, window, cx);
14891    }
14892
14893    pub fn add_selection_below(
14894        &mut self,
14895        action: &AddSelectionBelow,
14896        window: &mut Window,
14897        cx: &mut Context<Self>,
14898    ) {
14899        self.add_selection(false, action.skip_soft_wrap, window, cx);
14900    }
14901
14902    fn add_selection(
14903        &mut self,
14904        above: bool,
14905        skip_soft_wrap: bool,
14906        window: &mut Window,
14907        cx: &mut Context<Self>,
14908    ) {
14909        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14910
14911        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14912        let all_selections = self.selections.all::<Point>(&display_map);
14913        let text_layout_details = self.text_layout_details(window);
14914
14915        let (mut columnar_selections, new_selections_to_columnarize) = {
14916            if let Some(state) = self.add_selections_state.as_ref() {
14917                let columnar_selection_ids: HashSet<_> = state
14918                    .groups
14919                    .iter()
14920                    .flat_map(|group| group.stack.iter())
14921                    .copied()
14922                    .collect();
14923
14924                all_selections
14925                    .into_iter()
14926                    .partition(|s| columnar_selection_ids.contains(&s.id))
14927            } else {
14928                (Vec::new(), all_selections)
14929            }
14930        };
14931
14932        let mut state = self
14933            .add_selections_state
14934            .take()
14935            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14936
14937        for selection in new_selections_to_columnarize {
14938            let range = selection.display_range(&display_map).sorted();
14939            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14940            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14941            let positions = start_x.min(end_x)..start_x.max(end_x);
14942            let mut stack = Vec::new();
14943            for row in range.start.row().0..=range.end.row().0 {
14944                if let Some(selection) = self.selections.build_columnar_selection(
14945                    &display_map,
14946                    DisplayRow(row),
14947                    &positions,
14948                    selection.reversed,
14949                    &text_layout_details,
14950                ) {
14951                    stack.push(selection.id);
14952                    columnar_selections.push(selection);
14953                }
14954            }
14955            if !stack.is_empty() {
14956                if above {
14957                    stack.reverse();
14958                }
14959                state.groups.push(AddSelectionsGroup { above, stack });
14960            }
14961        }
14962
14963        let mut final_selections = Vec::new();
14964        let end_row = if above {
14965            DisplayRow(0)
14966        } else {
14967            display_map.max_point().row()
14968        };
14969
14970        let mut last_added_item_per_group = HashMap::default();
14971        for group in state.groups.iter_mut() {
14972            if let Some(last_id) = group.stack.last() {
14973                last_added_item_per_group.insert(*last_id, group);
14974            }
14975        }
14976
14977        for selection in columnar_selections {
14978            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14979                if above == group.above {
14980                    let range = selection.display_range(&display_map).sorted();
14981                    debug_assert_eq!(range.start.row(), range.end.row());
14982                    let mut row = range.start.row();
14983                    let positions =
14984                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14985                            Pixels::from(start)..Pixels::from(end)
14986                        } else {
14987                            let start_x =
14988                                display_map.x_for_display_point(range.start, &text_layout_details);
14989                            let end_x =
14990                                display_map.x_for_display_point(range.end, &text_layout_details);
14991                            start_x.min(end_x)..start_x.max(end_x)
14992                        };
14993
14994                    let mut maybe_new_selection = None;
14995                    let direction = if above { -1 } else { 1 };
14996
14997                    while row != end_row {
14998                        let new_buffer_row = if skip_soft_wrap {
14999                            let new_row = display_map
15000                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction);
15001                            row = new_row.row();
15002                            Some(new_row.to_point(&display_map).row)
15003                        } else {
15004                            if above {
15005                                row.0 -= 1;
15006                            } else {
15007                                row.0 += 1;
15008                            }
15009                            None
15010                        };
15011
15012                        let new_selection = if let Some(buffer_row) = new_buffer_row {
15013                            let start_col = selection.start.column;
15014                            let end_col = selection.end.column;
15015                            let buffer_columns = start_col.min(end_col)..start_col.max(end_col);
15016
15017                            self.selections
15018                                .build_columnar_selection_from_buffer_columns(
15019                                    &display_map,
15020                                    buffer_row,
15021                                    &buffer_columns,
15022                                    selection.reversed,
15023                                    &text_layout_details,
15024                                )
15025                        } else {
15026                            self.selections.build_columnar_selection(
15027                                &display_map,
15028                                row,
15029                                &positions,
15030                                selection.reversed,
15031                                &text_layout_details,
15032                            )
15033                        };
15034
15035                        if let Some(new_selection) = new_selection {
15036                            maybe_new_selection = Some(new_selection);
15037                            break;
15038                        }
15039                    }
15040
15041                    if let Some(new_selection) = maybe_new_selection {
15042                        group.stack.push(new_selection.id);
15043                        if above {
15044                            final_selections.push(new_selection);
15045                            final_selections.push(selection);
15046                        } else {
15047                            final_selections.push(selection);
15048                            final_selections.push(new_selection);
15049                        }
15050                    } else {
15051                        final_selections.push(selection);
15052                    }
15053                } else {
15054                    group.stack.pop();
15055                }
15056            } else {
15057                final_selections.push(selection);
15058            }
15059        }
15060
15061        self.change_selections(Default::default(), window, cx, |s| {
15062            s.select(final_selections);
15063        });
15064
15065        let final_selection_ids: HashSet<_> = self
15066            .selections
15067            .all::<Point>(&display_map)
15068            .iter()
15069            .map(|s| s.id)
15070            .collect();
15071        state.groups.retain_mut(|group| {
15072            // selections might get merged above so we remove invalid items from stacks
15073            group.stack.retain(|id| final_selection_ids.contains(id));
15074
15075            // single selection in stack can be treated as initial state
15076            group.stack.len() > 1
15077        });
15078
15079        if !state.groups.is_empty() {
15080            self.add_selections_state = Some(state);
15081        }
15082    }
15083
15084    pub fn insert_snippet_at_selections(
15085        &mut self,
15086        action: &InsertSnippet,
15087        window: &mut Window,
15088        cx: &mut Context<Self>,
15089    ) {
15090        self.try_insert_snippet_at_selections(action, window, cx)
15091            .log_err();
15092    }
15093
15094    fn try_insert_snippet_at_selections(
15095        &mut self,
15096        action: &InsertSnippet,
15097        window: &mut Window,
15098        cx: &mut Context<Self>,
15099    ) -> Result<()> {
15100        let insertion_ranges = self
15101            .selections
15102            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15103            .into_iter()
15104            .map(|selection| selection.range())
15105            .collect_vec();
15106
15107        let snippet = if let Some(snippet_body) = &action.snippet {
15108            if action.language.is_none() && action.name.is_none() {
15109                Snippet::parse(snippet_body)?
15110            } else {
15111                bail!("`snippet` is mutually exclusive with `language` and `name`")
15112            }
15113        } else if let Some(name) = &action.name {
15114            let project = self.project().context("no project")?;
15115            let snippet_store = project.read(cx).snippets().read(cx);
15116            let snippet = snippet_store
15117                .snippets_for(action.language.clone(), cx)
15118                .into_iter()
15119                .find(|snippet| snippet.name == *name)
15120                .context("snippet not found")?;
15121            Snippet::parse(&snippet.body)?
15122        } else {
15123            // todo(andrew): open modal to select snippet
15124            bail!("`name` or `snippet` is required")
15125        };
15126
15127        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15128    }
15129
15130    fn select_match_ranges(
15131        &mut self,
15132        range: Range<MultiBufferOffset>,
15133        reversed: bool,
15134        replace_newest: bool,
15135        auto_scroll: Option<Autoscroll>,
15136        window: &mut Window,
15137        cx: &mut Context<Editor>,
15138    ) {
15139        self.unfold_ranges(
15140            std::slice::from_ref(&range),
15141            false,
15142            auto_scroll.is_some(),
15143            cx,
15144        );
15145        let effects = if let Some(scroll) = auto_scroll {
15146            SelectionEffects::scroll(scroll)
15147        } else {
15148            SelectionEffects::no_scroll()
15149        };
15150        self.change_selections(effects, window, cx, |s| {
15151            if replace_newest {
15152                s.delete(s.newest_anchor().id);
15153            }
15154            if reversed {
15155                s.insert_range(range.end..range.start);
15156            } else {
15157                s.insert_range(range);
15158            }
15159        });
15160    }
15161
15162    pub fn select_next_match_internal(
15163        &mut self,
15164        display_map: &DisplaySnapshot,
15165        replace_newest: bool,
15166        autoscroll: Option<Autoscroll>,
15167        window: &mut Window,
15168        cx: &mut Context<Self>,
15169    ) -> Result<()> {
15170        let buffer = display_map.buffer_snapshot();
15171        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15172        if let Some(mut select_next_state) = self.select_next_state.take() {
15173            let query = &select_next_state.query;
15174            if !select_next_state.done {
15175                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15176                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15177                let mut next_selected_range = None;
15178
15179                let bytes_after_last_selection =
15180                    buffer.bytes_in_range(last_selection.end..buffer.len());
15181                let bytes_before_first_selection =
15182                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15183                let query_matches = query
15184                    .stream_find_iter(bytes_after_last_selection)
15185                    .map(|result| (last_selection.end, result))
15186                    .chain(
15187                        query
15188                            .stream_find_iter(bytes_before_first_selection)
15189                            .map(|result| (MultiBufferOffset(0), result)),
15190                    );
15191
15192                for (start_offset, query_match) in query_matches {
15193                    let query_match = query_match.unwrap(); // can only fail due to I/O
15194                    let offset_range =
15195                        start_offset + query_match.start()..start_offset + query_match.end();
15196
15197                    if !select_next_state.wordwise
15198                        || (!buffer.is_inside_word(offset_range.start, None)
15199                            && !buffer.is_inside_word(offset_range.end, None))
15200                    {
15201                        let idx = selections
15202                            .partition_point(|selection| selection.end <= offset_range.start);
15203                        let overlaps = selections
15204                            .get(idx)
15205                            .map_or(false, |selection| selection.start < offset_range.end);
15206
15207                        if !overlaps {
15208                            next_selected_range = Some(offset_range);
15209                            break;
15210                        }
15211                    }
15212                }
15213
15214                if let Some(next_selected_range) = next_selected_range {
15215                    self.select_match_ranges(
15216                        next_selected_range,
15217                        last_selection.reversed,
15218                        replace_newest,
15219                        autoscroll,
15220                        window,
15221                        cx,
15222                    );
15223                } else {
15224                    select_next_state.done = true;
15225                }
15226            }
15227
15228            self.select_next_state = Some(select_next_state);
15229        } else {
15230            let mut only_carets = true;
15231            let mut same_text_selected = true;
15232            let mut selected_text = None;
15233
15234            let mut selections_iter = selections.iter().peekable();
15235            while let Some(selection) = selections_iter.next() {
15236                if selection.start != selection.end {
15237                    only_carets = false;
15238                }
15239
15240                if same_text_selected {
15241                    if selected_text.is_none() {
15242                        selected_text =
15243                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15244                    }
15245
15246                    if let Some(next_selection) = selections_iter.peek() {
15247                        if next_selection.len() == selection.len() {
15248                            let next_selected_text = buffer
15249                                .text_for_range(next_selection.range())
15250                                .collect::<String>();
15251                            if Some(next_selected_text) != selected_text {
15252                                same_text_selected = false;
15253                                selected_text = None;
15254                            }
15255                        } else {
15256                            same_text_selected = false;
15257                            selected_text = None;
15258                        }
15259                    }
15260                }
15261            }
15262
15263            if only_carets {
15264                for selection in &mut selections {
15265                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15266                    selection.start = word_range.start;
15267                    selection.end = word_range.end;
15268                    selection.goal = SelectionGoal::None;
15269                    selection.reversed = false;
15270                    self.select_match_ranges(
15271                        selection.start..selection.end,
15272                        selection.reversed,
15273                        replace_newest,
15274                        autoscroll,
15275                        window,
15276                        cx,
15277                    );
15278                }
15279
15280                if selections.len() == 1 {
15281                    let selection = selections
15282                        .last()
15283                        .expect("ensured that there's only one selection");
15284                    let query = buffer
15285                        .text_for_range(selection.start..selection.end)
15286                        .collect::<String>();
15287                    let is_empty = query.is_empty();
15288                    let select_state = SelectNextState {
15289                        query: self.build_query(&[query], cx)?,
15290                        wordwise: true,
15291                        done: is_empty,
15292                    };
15293                    self.select_next_state = Some(select_state);
15294                } else {
15295                    self.select_next_state = None;
15296                }
15297            } else if let Some(selected_text) = selected_text {
15298                self.select_next_state = Some(SelectNextState {
15299                    query: self.build_query(&[selected_text], cx)?,
15300                    wordwise: false,
15301                    done: false,
15302                });
15303                self.select_next_match_internal(
15304                    display_map,
15305                    replace_newest,
15306                    autoscroll,
15307                    window,
15308                    cx,
15309                )?;
15310            }
15311        }
15312        Ok(())
15313    }
15314
15315    pub fn select_all_matches(
15316        &mut self,
15317        _action: &SelectAllMatches,
15318        window: &mut Window,
15319        cx: &mut Context<Self>,
15320    ) -> Result<()> {
15321        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15322
15323        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15324
15325        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15326        let Some(select_next_state) = self.select_next_state.as_mut() else {
15327            return Ok(());
15328        };
15329        if select_next_state.done {
15330            return Ok(());
15331        }
15332
15333        let mut new_selections = Vec::new();
15334
15335        let reversed = self
15336            .selections
15337            .oldest::<MultiBufferOffset>(&display_map)
15338            .reversed;
15339        let buffer = display_map.buffer_snapshot();
15340        let query_matches = select_next_state
15341            .query
15342            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15343
15344        for query_match in query_matches.into_iter() {
15345            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15346            let offset_range = if reversed {
15347                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15348            } else {
15349                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15350            };
15351
15352            if !select_next_state.wordwise
15353                || (!buffer.is_inside_word(offset_range.start, None)
15354                    && !buffer.is_inside_word(offset_range.end, None))
15355            {
15356                new_selections.push(offset_range.start..offset_range.end);
15357            }
15358        }
15359
15360        select_next_state.done = true;
15361
15362        if new_selections.is_empty() {
15363            log::error!("bug: new_selections is empty in select_all_matches");
15364            return Ok(());
15365        }
15366
15367        self.unfold_ranges(&new_selections.clone(), false, false, cx);
15368        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15369            selections.select_ranges(new_selections)
15370        });
15371
15372        Ok(())
15373    }
15374
15375    pub fn select_next(
15376        &mut self,
15377        action: &SelectNext,
15378        window: &mut Window,
15379        cx: &mut Context<Self>,
15380    ) -> Result<()> {
15381        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15382        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15383        self.select_next_match_internal(
15384            &display_map,
15385            action.replace_newest,
15386            Some(Autoscroll::newest()),
15387            window,
15388            cx,
15389        )?;
15390        Ok(())
15391    }
15392
15393    pub fn select_previous(
15394        &mut self,
15395        action: &SelectPrevious,
15396        window: &mut Window,
15397        cx: &mut Context<Self>,
15398    ) -> Result<()> {
15399        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15400        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15401        let buffer = display_map.buffer_snapshot();
15402        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15403        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15404            let query = &select_prev_state.query;
15405            if !select_prev_state.done {
15406                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15407                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15408                let mut next_selected_range = None;
15409                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15410                let bytes_before_last_selection =
15411                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15412                let bytes_after_first_selection =
15413                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15414                let query_matches = query
15415                    .stream_find_iter(bytes_before_last_selection)
15416                    .map(|result| (last_selection.start, result))
15417                    .chain(
15418                        query
15419                            .stream_find_iter(bytes_after_first_selection)
15420                            .map(|result| (buffer.len(), result)),
15421                    );
15422                for (end_offset, query_match) in query_matches {
15423                    let query_match = query_match.unwrap(); // can only fail due to I/O
15424                    let offset_range =
15425                        end_offset - query_match.end()..end_offset - query_match.start();
15426
15427                    if !select_prev_state.wordwise
15428                        || (!buffer.is_inside_word(offset_range.start, None)
15429                            && !buffer.is_inside_word(offset_range.end, None))
15430                    {
15431                        next_selected_range = Some(offset_range);
15432                        break;
15433                    }
15434                }
15435
15436                if let Some(next_selected_range) = next_selected_range {
15437                    self.select_match_ranges(
15438                        next_selected_range,
15439                        last_selection.reversed,
15440                        action.replace_newest,
15441                        Some(Autoscroll::newest()),
15442                        window,
15443                        cx,
15444                    );
15445                } else {
15446                    select_prev_state.done = true;
15447                }
15448            }
15449
15450            self.select_prev_state = Some(select_prev_state);
15451        } else {
15452            let mut only_carets = true;
15453            let mut same_text_selected = true;
15454            let mut selected_text = None;
15455
15456            let mut selections_iter = selections.iter().peekable();
15457            while let Some(selection) = selections_iter.next() {
15458                if selection.start != selection.end {
15459                    only_carets = false;
15460                }
15461
15462                if same_text_selected {
15463                    if selected_text.is_none() {
15464                        selected_text =
15465                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15466                    }
15467
15468                    if let Some(next_selection) = selections_iter.peek() {
15469                        if next_selection.len() == selection.len() {
15470                            let next_selected_text = buffer
15471                                .text_for_range(next_selection.range())
15472                                .collect::<String>();
15473                            if Some(next_selected_text) != selected_text {
15474                                same_text_selected = false;
15475                                selected_text = None;
15476                            }
15477                        } else {
15478                            same_text_selected = false;
15479                            selected_text = None;
15480                        }
15481                    }
15482                }
15483            }
15484
15485            if only_carets {
15486                for selection in &mut selections {
15487                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15488                    selection.start = word_range.start;
15489                    selection.end = word_range.end;
15490                    selection.goal = SelectionGoal::None;
15491                    selection.reversed = false;
15492                    self.select_match_ranges(
15493                        selection.start..selection.end,
15494                        selection.reversed,
15495                        action.replace_newest,
15496                        Some(Autoscroll::newest()),
15497                        window,
15498                        cx,
15499                    );
15500                }
15501                if selections.len() == 1 {
15502                    let selection = selections
15503                        .last()
15504                        .expect("ensured that there's only one selection");
15505                    let query = buffer
15506                        .text_for_range(selection.start..selection.end)
15507                        .collect::<String>();
15508                    let is_empty = query.is_empty();
15509                    let select_state = SelectNextState {
15510                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15511                        wordwise: true,
15512                        done: is_empty,
15513                    };
15514                    self.select_prev_state = Some(select_state);
15515                } else {
15516                    self.select_prev_state = None;
15517                }
15518            } else if let Some(selected_text) = selected_text {
15519                self.select_prev_state = Some(SelectNextState {
15520                    query: self
15521                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15522                    wordwise: false,
15523                    done: false,
15524                });
15525                self.select_previous(action, window, cx)?;
15526            }
15527        }
15528        Ok(())
15529    }
15530
15531    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15532    /// setting the case sensitivity based on the global
15533    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15534    /// editor's settings.
15535    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15536    where
15537        I: IntoIterator<Item = P>,
15538        P: AsRef<[u8]>,
15539    {
15540        let case_sensitive = self
15541            .select_next_is_case_sensitive
15542            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
15543
15544        let mut builder = AhoCorasickBuilder::new();
15545        builder.ascii_case_insensitive(!case_sensitive);
15546        builder.build(patterns)
15547    }
15548
15549    pub fn find_next_match(
15550        &mut self,
15551        _: &FindNextMatch,
15552        window: &mut Window,
15553        cx: &mut Context<Self>,
15554    ) -> Result<()> {
15555        let selections = self.selections.disjoint_anchors_arc();
15556        match selections.first() {
15557            Some(first) if selections.len() >= 2 => {
15558                self.change_selections(Default::default(), window, cx, |s| {
15559                    s.select_ranges([first.range()]);
15560                });
15561            }
15562            _ => self.select_next(
15563                &SelectNext {
15564                    replace_newest: true,
15565                },
15566                window,
15567                cx,
15568            )?,
15569        }
15570        Ok(())
15571    }
15572
15573    pub fn find_previous_match(
15574        &mut self,
15575        _: &FindPreviousMatch,
15576        window: &mut Window,
15577        cx: &mut Context<Self>,
15578    ) -> Result<()> {
15579        let selections = self.selections.disjoint_anchors_arc();
15580        match selections.last() {
15581            Some(last) if selections.len() >= 2 => {
15582                self.change_selections(Default::default(), window, cx, |s| {
15583                    s.select_ranges([last.range()]);
15584                });
15585            }
15586            _ => self.select_previous(
15587                &SelectPrevious {
15588                    replace_newest: true,
15589                },
15590                window,
15591                cx,
15592            )?,
15593        }
15594        Ok(())
15595    }
15596
15597    pub fn toggle_comments(
15598        &mut self,
15599        action: &ToggleComments,
15600        window: &mut Window,
15601        cx: &mut Context<Self>,
15602    ) {
15603        if self.read_only(cx) {
15604            return;
15605        }
15606        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15607        let text_layout_details = &self.text_layout_details(window);
15608        self.transact(window, cx, |this, window, cx| {
15609            let mut selections = this
15610                .selections
15611                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15612            let mut edits = Vec::new();
15613            let mut selection_edit_ranges = Vec::new();
15614            let mut last_toggled_row = None;
15615            let snapshot = this.buffer.read(cx).read(cx);
15616            let empty_str: Arc<str> = Arc::default();
15617            let mut suffixes_inserted = Vec::new();
15618            let ignore_indent = action.ignore_indent;
15619
15620            fn comment_prefix_range(
15621                snapshot: &MultiBufferSnapshot,
15622                row: MultiBufferRow,
15623                comment_prefix: &str,
15624                comment_prefix_whitespace: &str,
15625                ignore_indent: bool,
15626            ) -> Range<Point> {
15627                let indent_size = if ignore_indent {
15628                    0
15629                } else {
15630                    snapshot.indent_size_for_line(row).len
15631                };
15632
15633                let start = Point::new(row.0, indent_size);
15634
15635                let mut line_bytes = snapshot
15636                    .bytes_in_range(start..snapshot.max_point())
15637                    .flatten()
15638                    .copied();
15639
15640                // If this line currently begins with the line comment prefix, then record
15641                // the range containing the prefix.
15642                if line_bytes
15643                    .by_ref()
15644                    .take(comment_prefix.len())
15645                    .eq(comment_prefix.bytes())
15646                {
15647                    // Include any whitespace that matches the comment prefix.
15648                    let matching_whitespace_len = line_bytes
15649                        .zip(comment_prefix_whitespace.bytes())
15650                        .take_while(|(a, b)| a == b)
15651                        .count() as u32;
15652                    let end = Point::new(
15653                        start.row,
15654                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15655                    );
15656                    start..end
15657                } else {
15658                    start..start
15659                }
15660            }
15661
15662            fn comment_suffix_range(
15663                snapshot: &MultiBufferSnapshot,
15664                row: MultiBufferRow,
15665                comment_suffix: &str,
15666                comment_suffix_has_leading_space: bool,
15667            ) -> Range<Point> {
15668                let end = Point::new(row.0, snapshot.line_len(row));
15669                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15670
15671                let mut line_end_bytes = snapshot
15672                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15673                    .flatten()
15674                    .copied();
15675
15676                let leading_space_len = if suffix_start_column > 0
15677                    && line_end_bytes.next() == Some(b' ')
15678                    && comment_suffix_has_leading_space
15679                {
15680                    1
15681                } else {
15682                    0
15683                };
15684
15685                // If this line currently begins with the line comment prefix, then record
15686                // the range containing the prefix.
15687                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15688                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15689                    start..end
15690                } else {
15691                    end..end
15692                }
15693            }
15694
15695            // TODO: Handle selections that cross excerpts
15696            for selection in &mut selections {
15697                let start_column = snapshot
15698                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15699                    .len;
15700                let language = if let Some(language) =
15701                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15702                {
15703                    language
15704                } else {
15705                    continue;
15706                };
15707
15708                selection_edit_ranges.clear();
15709
15710                // If multiple selections contain a given row, avoid processing that
15711                // row more than once.
15712                let mut start_row = MultiBufferRow(selection.start.row);
15713                if last_toggled_row == Some(start_row) {
15714                    start_row = start_row.next_row();
15715                }
15716                let end_row =
15717                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15718                        MultiBufferRow(selection.end.row - 1)
15719                    } else {
15720                        MultiBufferRow(selection.end.row)
15721                    };
15722                last_toggled_row = Some(end_row);
15723
15724                if start_row > end_row {
15725                    continue;
15726                }
15727
15728                // If the language has line comments, toggle those.
15729                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15730
15731                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15732                if ignore_indent {
15733                    full_comment_prefixes = full_comment_prefixes
15734                        .into_iter()
15735                        .map(|s| Arc::from(s.trim_end()))
15736                        .collect();
15737                }
15738
15739                if !full_comment_prefixes.is_empty() {
15740                    let first_prefix = full_comment_prefixes
15741                        .first()
15742                        .expect("prefixes is non-empty");
15743                    let prefix_trimmed_lengths = full_comment_prefixes
15744                        .iter()
15745                        .map(|p| p.trim_end_matches(' ').len())
15746                        .collect::<SmallVec<[usize; 4]>>();
15747
15748                    let mut all_selection_lines_are_comments = true;
15749
15750                    for row in start_row.0..=end_row.0 {
15751                        let row = MultiBufferRow(row);
15752                        if start_row < end_row && snapshot.is_line_blank(row) {
15753                            continue;
15754                        }
15755
15756                        let prefix_range = full_comment_prefixes
15757                            .iter()
15758                            .zip(prefix_trimmed_lengths.iter().copied())
15759                            .map(|(prefix, trimmed_prefix_len)| {
15760                                comment_prefix_range(
15761                                    snapshot.deref(),
15762                                    row,
15763                                    &prefix[..trimmed_prefix_len],
15764                                    &prefix[trimmed_prefix_len..],
15765                                    ignore_indent,
15766                                )
15767                            })
15768                            .max_by_key(|range| range.end.column - range.start.column)
15769                            .expect("prefixes is non-empty");
15770
15771                        if prefix_range.is_empty() {
15772                            all_selection_lines_are_comments = false;
15773                        }
15774
15775                        selection_edit_ranges.push(prefix_range);
15776                    }
15777
15778                    if all_selection_lines_are_comments {
15779                        edits.extend(
15780                            selection_edit_ranges
15781                                .iter()
15782                                .cloned()
15783                                .map(|range| (range, empty_str.clone())),
15784                        );
15785                    } else {
15786                        let min_column = selection_edit_ranges
15787                            .iter()
15788                            .map(|range| range.start.column)
15789                            .min()
15790                            .unwrap_or(0);
15791                        edits.extend(selection_edit_ranges.iter().map(|range| {
15792                            let position = Point::new(range.start.row, min_column);
15793                            (position..position, first_prefix.clone())
15794                        }));
15795                    }
15796                } else if let Some(BlockCommentConfig {
15797                    start: full_comment_prefix,
15798                    end: comment_suffix,
15799                    ..
15800                }) = language.block_comment()
15801                {
15802                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15803                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15804                    let prefix_range = comment_prefix_range(
15805                        snapshot.deref(),
15806                        start_row,
15807                        comment_prefix,
15808                        comment_prefix_whitespace,
15809                        ignore_indent,
15810                    );
15811                    let suffix_range = comment_suffix_range(
15812                        snapshot.deref(),
15813                        end_row,
15814                        comment_suffix.trim_start_matches(' '),
15815                        comment_suffix.starts_with(' '),
15816                    );
15817
15818                    if prefix_range.is_empty() || suffix_range.is_empty() {
15819                        edits.push((
15820                            prefix_range.start..prefix_range.start,
15821                            full_comment_prefix.clone(),
15822                        ));
15823                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15824                        suffixes_inserted.push((end_row, comment_suffix.len()));
15825                    } else {
15826                        edits.push((prefix_range, empty_str.clone()));
15827                        edits.push((suffix_range, empty_str.clone()));
15828                    }
15829                } else {
15830                    continue;
15831                }
15832            }
15833
15834            drop(snapshot);
15835            this.buffer.update(cx, |buffer, cx| {
15836                buffer.edit(edits, None, cx);
15837            });
15838
15839            // Adjust selections so that they end before any comment suffixes that
15840            // were inserted.
15841            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15842            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15843            let snapshot = this.buffer.read(cx).read(cx);
15844            for selection in &mut selections {
15845                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15846                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15847                        Ordering::Less => {
15848                            suffixes_inserted.next();
15849                            continue;
15850                        }
15851                        Ordering::Greater => break,
15852                        Ordering::Equal => {
15853                            if selection.end.column == snapshot.line_len(row) {
15854                                if selection.is_empty() {
15855                                    selection.start.column -= suffix_len as u32;
15856                                }
15857                                selection.end.column -= suffix_len as u32;
15858                            }
15859                            break;
15860                        }
15861                    }
15862                }
15863            }
15864
15865            drop(snapshot);
15866            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15867
15868            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15869            let selections_on_single_row = selections.windows(2).all(|selections| {
15870                selections[0].start.row == selections[1].start.row
15871                    && selections[0].end.row == selections[1].end.row
15872                    && selections[0].start.row == selections[0].end.row
15873            });
15874            let selections_selecting = selections
15875                .iter()
15876                .any(|selection| selection.start != selection.end);
15877            let advance_downwards = action.advance_downwards
15878                && selections_on_single_row
15879                && !selections_selecting
15880                && !matches!(this.mode, EditorMode::SingleLine);
15881
15882            if advance_downwards {
15883                let snapshot = this.buffer.read(cx).snapshot(cx);
15884
15885                this.change_selections(Default::default(), window, cx, |s| {
15886                    s.move_cursors_with(|display_snapshot, display_point, _| {
15887                        let mut point = display_point.to_point(display_snapshot);
15888                        point.row += 1;
15889                        point = snapshot.clip_point(point, Bias::Left);
15890                        let display_point = point.to_display_point(display_snapshot);
15891                        let goal = SelectionGoal::HorizontalPosition(
15892                            display_snapshot
15893                                .x_for_display_point(display_point, text_layout_details)
15894                                .into(),
15895                        );
15896                        (display_point, goal)
15897                    })
15898                });
15899            }
15900        });
15901    }
15902
15903    pub fn select_enclosing_symbol(
15904        &mut self,
15905        _: &SelectEnclosingSymbol,
15906        window: &mut Window,
15907        cx: &mut Context<Self>,
15908    ) {
15909        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15910
15911        let buffer = self.buffer.read(cx).snapshot(cx);
15912        let old_selections = self
15913            .selections
15914            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15915            .into_boxed_slice();
15916
15917        fn update_selection(
15918            selection: &Selection<MultiBufferOffset>,
15919            buffer_snap: &MultiBufferSnapshot,
15920        ) -> Option<Selection<MultiBufferOffset>> {
15921            let cursor = selection.head();
15922            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15923            for symbol in symbols.iter().rev() {
15924                let start = symbol.range.start.to_offset(buffer_snap);
15925                let end = symbol.range.end.to_offset(buffer_snap);
15926                let new_range = start..end;
15927                if start < selection.start || end > selection.end {
15928                    return Some(Selection {
15929                        id: selection.id,
15930                        start: new_range.start,
15931                        end: new_range.end,
15932                        goal: SelectionGoal::None,
15933                        reversed: selection.reversed,
15934                    });
15935                }
15936            }
15937            None
15938        }
15939
15940        let mut selected_larger_symbol = false;
15941        let new_selections = old_selections
15942            .iter()
15943            .map(|selection| match update_selection(selection, &buffer) {
15944                Some(new_selection) => {
15945                    if new_selection.range() != selection.range() {
15946                        selected_larger_symbol = true;
15947                    }
15948                    new_selection
15949                }
15950                None => selection.clone(),
15951            })
15952            .collect::<Vec<_>>();
15953
15954        if selected_larger_symbol {
15955            self.change_selections(Default::default(), window, cx, |s| {
15956                s.select(new_selections);
15957            });
15958        }
15959    }
15960
15961    pub fn select_larger_syntax_node(
15962        &mut self,
15963        _: &SelectLargerSyntaxNode,
15964        window: &mut Window,
15965        cx: &mut Context<Self>,
15966    ) {
15967        let Some(visible_row_count) = self.visible_row_count() else {
15968            return;
15969        };
15970        let old_selections: Box<[_]> = self
15971            .selections
15972            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15973            .into();
15974        if old_selections.is_empty() {
15975            return;
15976        }
15977
15978        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15979
15980        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15981        let buffer = self.buffer.read(cx).snapshot(cx);
15982
15983        let mut selected_larger_node = false;
15984        let mut new_selections = old_selections
15985            .iter()
15986            .map(|selection| {
15987                let old_range = selection.start..selection.end;
15988
15989                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15990                    // manually select word at selection
15991                    if ["string_content", "inline"].contains(&node.kind()) {
15992                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15993                        // ignore if word is already selected
15994                        if !word_range.is_empty() && old_range != word_range {
15995                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15996                            // only select word if start and end point belongs to same word
15997                            if word_range == last_word_range {
15998                                selected_larger_node = true;
15999                                return Selection {
16000                                    id: selection.id,
16001                                    start: word_range.start,
16002                                    end: word_range.end,
16003                                    goal: SelectionGoal::None,
16004                                    reversed: selection.reversed,
16005                                };
16006                            }
16007                        }
16008                    }
16009                }
16010
16011                let mut new_range = old_range.clone();
16012                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
16013                    new_range = range;
16014                    if !node.is_named() {
16015                        continue;
16016                    }
16017                    if !display_map.intersects_fold(new_range.start)
16018                        && !display_map.intersects_fold(new_range.end)
16019                    {
16020                        break;
16021                    }
16022                }
16023
16024                selected_larger_node |= new_range != old_range;
16025                Selection {
16026                    id: selection.id,
16027                    start: new_range.start,
16028                    end: new_range.end,
16029                    goal: SelectionGoal::None,
16030                    reversed: selection.reversed,
16031                }
16032            })
16033            .collect::<Vec<_>>();
16034
16035        if !selected_larger_node {
16036            return; // don't put this call in the history
16037        }
16038
16039        // scroll based on transformation done to the last selection created by the user
16040        let (last_old, last_new) = old_selections
16041            .last()
16042            .zip(new_selections.last().cloned())
16043            .expect("old_selections isn't empty");
16044
16045        // revert selection
16046        let is_selection_reversed = {
16047            let should_newest_selection_be_reversed = last_old.start != last_new.start;
16048            new_selections.last_mut().expect("checked above").reversed =
16049                should_newest_selection_be_reversed;
16050            should_newest_selection_be_reversed
16051        };
16052
16053        if selected_larger_node {
16054            self.select_syntax_node_history.disable_clearing = true;
16055            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16056                s.select(new_selections.clone());
16057            });
16058            self.select_syntax_node_history.disable_clearing = false;
16059        }
16060
16061        let start_row = last_new.start.to_display_point(&display_map).row().0;
16062        let end_row = last_new.end.to_display_point(&display_map).row().0;
16063        let selection_height = end_row - start_row + 1;
16064        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16065
16066        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16067        let scroll_behavior = if fits_on_the_screen {
16068            self.request_autoscroll(Autoscroll::fit(), cx);
16069            SelectSyntaxNodeScrollBehavior::FitSelection
16070        } else if is_selection_reversed {
16071            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16072            SelectSyntaxNodeScrollBehavior::CursorTop
16073        } else {
16074            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16075            SelectSyntaxNodeScrollBehavior::CursorBottom
16076        };
16077
16078        self.select_syntax_node_history.push((
16079            old_selections,
16080            scroll_behavior,
16081            is_selection_reversed,
16082        ));
16083    }
16084
16085    pub fn select_smaller_syntax_node(
16086        &mut self,
16087        _: &SelectSmallerSyntaxNode,
16088        window: &mut Window,
16089        cx: &mut Context<Self>,
16090    ) {
16091        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16092
16093        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16094            self.select_syntax_node_history.pop()
16095        {
16096            if let Some(selection) = selections.last_mut() {
16097                selection.reversed = is_selection_reversed;
16098            }
16099
16100            self.select_syntax_node_history.disable_clearing = true;
16101            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16102                s.select(selections.to_vec());
16103            });
16104            self.select_syntax_node_history.disable_clearing = false;
16105
16106            match scroll_behavior {
16107                SelectSyntaxNodeScrollBehavior::CursorTop => {
16108                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16109                }
16110                SelectSyntaxNodeScrollBehavior::FitSelection => {
16111                    self.request_autoscroll(Autoscroll::fit(), cx);
16112                }
16113                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16114                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16115                }
16116            }
16117        }
16118    }
16119
16120    pub fn unwrap_syntax_node(
16121        &mut self,
16122        _: &UnwrapSyntaxNode,
16123        window: &mut Window,
16124        cx: &mut Context<Self>,
16125    ) {
16126        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16127
16128        let buffer = self.buffer.read(cx).snapshot(cx);
16129        let selections = self
16130            .selections
16131            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16132            .into_iter()
16133            // subtracting the offset requires sorting
16134            .sorted_by_key(|i| i.start);
16135
16136        let full_edits = selections
16137            .into_iter()
16138            .filter_map(|selection| {
16139                let child = if selection.is_empty()
16140                    && let Some((_, ancestor_range)) =
16141                        buffer.syntax_ancestor(selection.start..selection.end)
16142                {
16143                    ancestor_range
16144                } else {
16145                    selection.range()
16146                };
16147
16148                let mut parent = child.clone();
16149                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16150                    parent = ancestor_range;
16151                    if parent.start < child.start || parent.end > child.end {
16152                        break;
16153                    }
16154                }
16155
16156                if parent == child {
16157                    return None;
16158                }
16159                let text = buffer.text_for_range(child).collect::<String>();
16160                Some((selection.id, parent, text))
16161            })
16162            .collect::<Vec<_>>();
16163        if full_edits.is_empty() {
16164            return;
16165        }
16166
16167        self.transact(window, cx, |this, window, cx| {
16168            this.buffer.update(cx, |buffer, cx| {
16169                buffer.edit(
16170                    full_edits
16171                        .iter()
16172                        .map(|(_, p, t)| (p.clone(), t.clone()))
16173                        .collect::<Vec<_>>(),
16174                    None,
16175                    cx,
16176                );
16177            });
16178            this.change_selections(Default::default(), window, cx, |s| {
16179                let mut offset = 0;
16180                let mut selections = vec![];
16181                for (id, parent, text) in full_edits {
16182                    let start = parent.start - offset;
16183                    offset += (parent.end - parent.start) - text.len();
16184                    selections.push(Selection {
16185                        id,
16186                        start,
16187                        end: start + text.len(),
16188                        reversed: false,
16189                        goal: Default::default(),
16190                    });
16191                }
16192                s.select(selections);
16193            });
16194        });
16195    }
16196
16197    pub fn select_next_syntax_node(
16198        &mut self,
16199        _: &SelectNextSyntaxNode,
16200        window: &mut Window,
16201        cx: &mut Context<Self>,
16202    ) {
16203        let old_selections: Box<[_]> = self
16204            .selections
16205            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16206            .into();
16207        if old_selections.is_empty() {
16208            return;
16209        }
16210
16211        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16212
16213        let buffer = self.buffer.read(cx).snapshot(cx);
16214        let mut selected_sibling = false;
16215
16216        let new_selections = old_selections
16217            .iter()
16218            .map(|selection| {
16219                let old_range = selection.start..selection.end;
16220
16221                let old_range =
16222                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16223                let excerpt = buffer.excerpt_containing(old_range.clone());
16224
16225                if let Some(mut excerpt) = excerpt
16226                    && let Some(node) = excerpt
16227                        .buffer()
16228                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16229                {
16230                    let new_range = excerpt.map_range_from_buffer(
16231                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16232                    );
16233                    selected_sibling = true;
16234                    Selection {
16235                        id: selection.id,
16236                        start: new_range.start,
16237                        end: new_range.end,
16238                        goal: SelectionGoal::None,
16239                        reversed: selection.reversed,
16240                    }
16241                } else {
16242                    selection.clone()
16243                }
16244            })
16245            .collect::<Vec<_>>();
16246
16247        if selected_sibling {
16248            self.change_selections(
16249                SelectionEffects::scroll(Autoscroll::fit()),
16250                window,
16251                cx,
16252                |s| {
16253                    s.select(new_selections);
16254                },
16255            );
16256        }
16257    }
16258
16259    pub fn select_prev_syntax_node(
16260        &mut self,
16261        _: &SelectPreviousSyntaxNode,
16262        window: &mut Window,
16263        cx: &mut Context<Self>,
16264    ) {
16265        let old_selections: Box<[_]> = self
16266            .selections
16267            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16268            .into();
16269        if old_selections.is_empty() {
16270            return;
16271        }
16272
16273        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16274
16275        let buffer = self.buffer.read(cx).snapshot(cx);
16276        let mut selected_sibling = false;
16277
16278        let new_selections = old_selections
16279            .iter()
16280            .map(|selection| {
16281                let old_range = selection.start..selection.end;
16282                let old_range =
16283                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16284                let excerpt = buffer.excerpt_containing(old_range.clone());
16285
16286                if let Some(mut excerpt) = excerpt
16287                    && let Some(node) = excerpt
16288                        .buffer()
16289                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16290                {
16291                    let new_range = excerpt.map_range_from_buffer(
16292                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16293                    );
16294                    selected_sibling = true;
16295                    Selection {
16296                        id: selection.id,
16297                        start: new_range.start,
16298                        end: new_range.end,
16299                        goal: SelectionGoal::None,
16300                        reversed: selection.reversed,
16301                    }
16302                } else {
16303                    selection.clone()
16304                }
16305            })
16306            .collect::<Vec<_>>();
16307
16308        if selected_sibling {
16309            self.change_selections(
16310                SelectionEffects::scroll(Autoscroll::fit()),
16311                window,
16312                cx,
16313                |s| {
16314                    s.select(new_selections);
16315                },
16316            );
16317        }
16318    }
16319
16320    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16321        if !EditorSettings::get_global(cx).gutter.runnables {
16322            self.clear_tasks();
16323            return Task::ready(());
16324        }
16325        let project = self.project().map(Entity::downgrade);
16326        let task_sources = self.lsp_task_sources(cx);
16327        let multi_buffer = self.buffer.downgrade();
16328        cx.spawn_in(window, async move |editor, cx| {
16329            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16330            let Some(project) = project.and_then(|p| p.upgrade()) else {
16331                return;
16332            };
16333            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16334                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16335            }) else {
16336                return;
16337            };
16338
16339            let hide_runnables = project
16340                .update(cx, |project, _| project.is_via_collab())
16341                .unwrap_or(true);
16342            if hide_runnables {
16343                return;
16344            }
16345            let new_rows =
16346                cx.background_spawn({
16347                    let snapshot = display_snapshot.clone();
16348                    async move {
16349                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16350                    }
16351                })
16352                    .await;
16353            let Ok(lsp_tasks) =
16354                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16355            else {
16356                return;
16357            };
16358            let lsp_tasks = lsp_tasks.await;
16359
16360            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16361                lsp_tasks
16362                    .into_iter()
16363                    .flat_map(|(kind, tasks)| {
16364                        tasks.into_iter().filter_map(move |(location, task)| {
16365                            Some((kind.clone(), location?, task))
16366                        })
16367                    })
16368                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16369                        let buffer = location.target.buffer;
16370                        let buffer_snapshot = buffer.read(cx).snapshot();
16371                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16372                            |(excerpt_id, snapshot, _)| {
16373                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16374                                    display_snapshot
16375                                        .buffer_snapshot()
16376                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16377                                } else {
16378                                    None
16379                                }
16380                            },
16381                        );
16382                        if let Some(offset) = offset {
16383                            let task_buffer_range =
16384                                location.target.range.to_point(&buffer_snapshot);
16385                            let context_buffer_range =
16386                                task_buffer_range.to_offset(&buffer_snapshot);
16387                            let context_range = BufferOffset(context_buffer_range.start)
16388                                ..BufferOffset(context_buffer_range.end);
16389
16390                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16391                                .or_insert_with(|| RunnableTasks {
16392                                    templates: Vec::new(),
16393                                    offset,
16394                                    column: task_buffer_range.start.column,
16395                                    extra_variables: HashMap::default(),
16396                                    context_range,
16397                                })
16398                                .templates
16399                                .push((kind, task.original_task().clone()));
16400                        }
16401
16402                        acc
16403                    })
16404            }) else {
16405                return;
16406            };
16407
16408            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16409                buffer.language_settings(cx).tasks.prefer_lsp
16410            }) else {
16411                return;
16412            };
16413
16414            let rows = Self::runnable_rows(
16415                project,
16416                display_snapshot,
16417                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16418                new_rows,
16419                cx.clone(),
16420            )
16421            .await;
16422            editor
16423                .update(cx, |editor, _| {
16424                    editor.clear_tasks();
16425                    for (key, mut value) in rows {
16426                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16427                            value.templates.extend(lsp_tasks.templates);
16428                        }
16429
16430                        editor.insert_tasks(key, value);
16431                    }
16432                    for (key, value) in lsp_tasks_by_rows {
16433                        editor.insert_tasks(key, value);
16434                    }
16435                })
16436                .ok();
16437        })
16438    }
16439    fn fetch_runnable_ranges(
16440        snapshot: &DisplaySnapshot,
16441        range: Range<Anchor>,
16442    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16443        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16444    }
16445
16446    fn runnable_rows(
16447        project: Entity<Project>,
16448        snapshot: DisplaySnapshot,
16449        prefer_lsp: bool,
16450        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16451        cx: AsyncWindowContext,
16452    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16453        cx.spawn(async move |cx| {
16454            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16455            for (run_range, mut runnable) in runnable_ranges {
16456                let Some(tasks) = cx
16457                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16458                    .ok()
16459                else {
16460                    continue;
16461                };
16462                let mut tasks = tasks.await;
16463
16464                if prefer_lsp {
16465                    tasks.retain(|(task_kind, _)| {
16466                        !matches!(task_kind, TaskSourceKind::Language { .. })
16467                    });
16468                }
16469                if tasks.is_empty() {
16470                    continue;
16471                }
16472
16473                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16474                let Some(row) = snapshot
16475                    .buffer_snapshot()
16476                    .buffer_line_for_row(MultiBufferRow(point.row))
16477                    .map(|(_, range)| range.start.row)
16478                else {
16479                    continue;
16480                };
16481
16482                let context_range =
16483                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16484                runnable_rows.push((
16485                    (runnable.buffer_id, row),
16486                    RunnableTasks {
16487                        templates: tasks,
16488                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16489                        context_range,
16490                        column: point.column,
16491                        extra_variables: runnable.extra_captures,
16492                    },
16493                ));
16494            }
16495            runnable_rows
16496        })
16497    }
16498
16499    fn templates_with_tags(
16500        project: &Entity<Project>,
16501        runnable: &mut Runnable,
16502        cx: &mut App,
16503    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16504        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16505            let (worktree_id, file) = project
16506                .buffer_for_id(runnable.buffer, cx)
16507                .and_then(|buffer| buffer.read(cx).file())
16508                .map(|file| (file.worktree_id(cx), file.clone()))
16509                .unzip();
16510
16511            (
16512                project.task_store().read(cx).task_inventory().cloned(),
16513                worktree_id,
16514                file,
16515            )
16516        });
16517
16518        let tags = mem::take(&mut runnable.tags);
16519        let language = runnable.language.clone();
16520        cx.spawn(async move |cx| {
16521            let mut templates_with_tags = Vec::new();
16522            if let Some(inventory) = inventory {
16523                for RunnableTag(tag) in tags {
16524                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16525                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16526                    }) else {
16527                        return templates_with_tags;
16528                    };
16529                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16530                        move |(_, template)| {
16531                            template.tags.iter().any(|source_tag| source_tag == &tag)
16532                        },
16533                    ));
16534                }
16535            }
16536            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16537
16538            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16539                // Strongest source wins; if we have worktree tag binding, prefer that to
16540                // global and language bindings;
16541                // if we have a global binding, prefer that to language binding.
16542                let first_mismatch = templates_with_tags
16543                    .iter()
16544                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16545                if let Some(index) = first_mismatch {
16546                    templates_with_tags.truncate(index);
16547                }
16548            }
16549
16550            templates_with_tags
16551        })
16552    }
16553
16554    pub fn move_to_enclosing_bracket(
16555        &mut self,
16556        _: &MoveToEnclosingBracket,
16557        window: &mut Window,
16558        cx: &mut Context<Self>,
16559    ) {
16560        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16561        self.change_selections(Default::default(), window, cx, |s| {
16562            s.move_offsets_with(|snapshot, selection| {
16563                let Some(enclosing_bracket_ranges) =
16564                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16565                else {
16566                    return;
16567                };
16568
16569                let mut best_length = usize::MAX;
16570                let mut best_inside = false;
16571                let mut best_in_bracket_range = false;
16572                let mut best_destination = None;
16573                for (open, close) in enclosing_bracket_ranges {
16574                    let close = close.to_inclusive();
16575                    let length = *close.end() - open.start;
16576                    let inside = selection.start >= open.end && selection.end <= *close.start();
16577                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16578                        || close.contains(&selection.head());
16579
16580                    // If best is next to a bracket and current isn't, skip
16581                    if !in_bracket_range && best_in_bracket_range {
16582                        continue;
16583                    }
16584
16585                    // Prefer smaller lengths unless best is inside and current isn't
16586                    if length > best_length && (best_inside || !inside) {
16587                        continue;
16588                    }
16589
16590                    best_length = length;
16591                    best_inside = inside;
16592                    best_in_bracket_range = in_bracket_range;
16593                    best_destination = Some(
16594                        if close.contains(&selection.start) && close.contains(&selection.end) {
16595                            if inside { open.end } else { open.start }
16596                        } else if inside {
16597                            *close.start()
16598                        } else {
16599                            *close.end()
16600                        },
16601                    );
16602                }
16603
16604                if let Some(destination) = best_destination {
16605                    selection.collapse_to(destination, SelectionGoal::None);
16606                }
16607            })
16608        });
16609    }
16610
16611    pub fn undo_selection(
16612        &mut self,
16613        _: &UndoSelection,
16614        window: &mut Window,
16615        cx: &mut Context<Self>,
16616    ) {
16617        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16618        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16619            self.selection_history.mode = SelectionHistoryMode::Undoing;
16620            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16621                this.end_selection(window, cx);
16622                this.change_selections(
16623                    SelectionEffects::scroll(Autoscroll::newest()),
16624                    window,
16625                    cx,
16626                    |s| s.select_anchors(entry.selections.to_vec()),
16627                );
16628            });
16629            self.selection_history.mode = SelectionHistoryMode::Normal;
16630
16631            self.select_next_state = entry.select_next_state;
16632            self.select_prev_state = entry.select_prev_state;
16633            self.add_selections_state = entry.add_selections_state;
16634        }
16635    }
16636
16637    pub fn redo_selection(
16638        &mut self,
16639        _: &RedoSelection,
16640        window: &mut Window,
16641        cx: &mut Context<Self>,
16642    ) {
16643        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16644        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16645            self.selection_history.mode = SelectionHistoryMode::Redoing;
16646            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16647                this.end_selection(window, cx);
16648                this.change_selections(
16649                    SelectionEffects::scroll(Autoscroll::newest()),
16650                    window,
16651                    cx,
16652                    |s| s.select_anchors(entry.selections.to_vec()),
16653                );
16654            });
16655            self.selection_history.mode = SelectionHistoryMode::Normal;
16656
16657            self.select_next_state = entry.select_next_state;
16658            self.select_prev_state = entry.select_prev_state;
16659            self.add_selections_state = entry.add_selections_state;
16660        }
16661    }
16662
16663    pub fn expand_excerpts(
16664        &mut self,
16665        action: &ExpandExcerpts,
16666        _: &mut Window,
16667        cx: &mut Context<Self>,
16668    ) {
16669        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16670    }
16671
16672    pub fn expand_excerpts_down(
16673        &mut self,
16674        action: &ExpandExcerptsDown,
16675        _: &mut Window,
16676        cx: &mut Context<Self>,
16677    ) {
16678        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16679    }
16680
16681    pub fn expand_excerpts_up(
16682        &mut self,
16683        action: &ExpandExcerptsUp,
16684        _: &mut Window,
16685        cx: &mut Context<Self>,
16686    ) {
16687        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16688    }
16689
16690    pub fn expand_excerpts_for_direction(
16691        &mut self,
16692        lines: u32,
16693        direction: ExpandExcerptDirection,
16694        cx: &mut Context<Self>,
16695    ) {
16696        let selections = self.selections.disjoint_anchors_arc();
16697
16698        let lines = if lines == 0 {
16699            EditorSettings::get_global(cx).expand_excerpt_lines
16700        } else {
16701            lines
16702        };
16703
16704        let snapshot = self.buffer.read(cx).snapshot(cx);
16705        let mut excerpt_ids = selections
16706            .iter()
16707            .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16708            .collect::<Vec<_>>();
16709        excerpt_ids.sort();
16710        excerpt_ids.dedup();
16711
16712        if self.delegate_expand_excerpts {
16713            cx.emit(EditorEvent::ExpandExcerptsRequested {
16714                excerpt_ids,
16715                lines,
16716                direction,
16717            });
16718            return;
16719        }
16720
16721        self.buffer.update(cx, |buffer, cx| {
16722            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16723        })
16724    }
16725
16726    pub fn expand_excerpt(
16727        &mut self,
16728        excerpt: ExcerptId,
16729        direction: ExpandExcerptDirection,
16730        window: &mut Window,
16731        cx: &mut Context<Self>,
16732    ) {
16733        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16734
16735        if self.delegate_expand_excerpts {
16736            cx.emit(EditorEvent::ExpandExcerptsRequested {
16737                excerpt_ids: vec![excerpt],
16738                lines: lines_to_expand,
16739                direction,
16740            });
16741            return;
16742        }
16743
16744        let current_scroll_position = self.scroll_position(cx);
16745        let mut scroll = None;
16746
16747        if direction == ExpandExcerptDirection::Down {
16748            let multi_buffer = self.buffer.read(cx);
16749            let snapshot = multi_buffer.snapshot(cx);
16750            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16751                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16752                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16753            {
16754                let buffer_snapshot = buffer.read(cx).snapshot();
16755                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16756                let last_row = buffer_snapshot.max_point().row;
16757                let lines_below = last_row.saturating_sub(excerpt_end_row);
16758                if lines_below >= lines_to_expand {
16759                    scroll = Some(
16760                        current_scroll_position
16761                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16762                    );
16763                }
16764            }
16765        }
16766        if direction == ExpandExcerptDirection::Up
16767            && self
16768                .buffer
16769                .read(cx)
16770                .snapshot(cx)
16771                .excerpt_before(excerpt)
16772                .is_none()
16773        {
16774            scroll = Some(current_scroll_position);
16775        }
16776
16777        self.buffer.update(cx, |buffer, cx| {
16778            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16779        });
16780
16781        if let Some(new_scroll_position) = scroll {
16782            self.set_scroll_position(new_scroll_position, window, cx);
16783        }
16784    }
16785
16786    pub fn go_to_singleton_buffer_point(
16787        &mut self,
16788        point: Point,
16789        window: &mut Window,
16790        cx: &mut Context<Self>,
16791    ) {
16792        self.go_to_singleton_buffer_range(point..point, window, cx);
16793    }
16794
16795    pub fn go_to_singleton_buffer_range(
16796        &mut self,
16797        range: Range<Point>,
16798        window: &mut Window,
16799        cx: &mut Context<Self>,
16800    ) {
16801        let multibuffer = self.buffer().read(cx);
16802        let Some(buffer) = multibuffer.as_singleton() else {
16803            return;
16804        };
16805        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16806            return;
16807        };
16808        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16809            return;
16810        };
16811        self.change_selections(
16812            SelectionEffects::default().nav_history(true),
16813            window,
16814            cx,
16815            |s| s.select_anchor_ranges([start..end]),
16816        );
16817    }
16818
16819    pub fn go_to_diagnostic(
16820        &mut self,
16821        action: &GoToDiagnostic,
16822        window: &mut Window,
16823        cx: &mut Context<Self>,
16824    ) {
16825        if !self.diagnostics_enabled() {
16826            return;
16827        }
16828        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16829        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16830    }
16831
16832    pub fn go_to_prev_diagnostic(
16833        &mut self,
16834        action: &GoToPreviousDiagnostic,
16835        window: &mut Window,
16836        cx: &mut Context<Self>,
16837    ) {
16838        if !self.diagnostics_enabled() {
16839            return;
16840        }
16841        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16842        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16843    }
16844
16845    pub fn go_to_diagnostic_impl(
16846        &mut self,
16847        direction: Direction,
16848        severity: GoToDiagnosticSeverityFilter,
16849        window: &mut Window,
16850        cx: &mut Context<Self>,
16851    ) {
16852        let buffer = self.buffer.read(cx).snapshot(cx);
16853        let selection = self
16854            .selections
16855            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16856
16857        let mut active_group_id = None;
16858        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16859            && active_group.active_range.start.to_offset(&buffer) == selection.start
16860        {
16861            active_group_id = Some(active_group.group_id);
16862        }
16863
16864        fn filtered<'a>(
16865            severity: GoToDiagnosticSeverityFilter,
16866            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16867        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16868            diagnostics
16869                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16870                .filter(|entry| entry.range.start != entry.range.end)
16871                .filter(|entry| !entry.diagnostic.is_unnecessary)
16872        }
16873
16874        let before = filtered(
16875            severity,
16876            buffer
16877                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16878                .filter(|entry| entry.range.start <= selection.start),
16879        );
16880        let after = filtered(
16881            severity,
16882            buffer
16883                .diagnostics_in_range(selection.start..buffer.len())
16884                .filter(|entry| entry.range.start >= selection.start),
16885        );
16886
16887        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16888        if direction == Direction::Prev {
16889            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16890            {
16891                for diagnostic in prev_diagnostics.into_iter().rev() {
16892                    if diagnostic.range.start != selection.start
16893                        || active_group_id
16894                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16895                    {
16896                        found = Some(diagnostic);
16897                        break 'outer;
16898                    }
16899                }
16900            }
16901        } else {
16902            for diagnostic in after.chain(before) {
16903                if diagnostic.range.start != selection.start
16904                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16905                {
16906                    found = Some(diagnostic);
16907                    break;
16908                }
16909            }
16910        }
16911        let Some(next_diagnostic) = found else {
16912            return;
16913        };
16914
16915        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16916        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16917            return;
16918        };
16919        let snapshot = self.snapshot(window, cx);
16920        if snapshot.intersects_fold(next_diagnostic.range.start) {
16921            self.unfold_ranges(
16922                std::slice::from_ref(&next_diagnostic.range),
16923                true,
16924                false,
16925                cx,
16926            );
16927        }
16928        self.change_selections(Default::default(), window, cx, |s| {
16929            s.select_ranges(vec![
16930                next_diagnostic.range.start..next_diagnostic.range.start,
16931            ])
16932        });
16933        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16934        self.refresh_edit_prediction(false, true, window, cx);
16935    }
16936
16937    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16938        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16939        let snapshot = self.snapshot(window, cx);
16940        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16941        self.go_to_hunk_before_or_after_position(
16942            &snapshot,
16943            selection.head(),
16944            Direction::Next,
16945            window,
16946            cx,
16947        );
16948    }
16949
16950    pub fn go_to_hunk_before_or_after_position(
16951        &mut self,
16952        snapshot: &EditorSnapshot,
16953        position: Point,
16954        direction: Direction,
16955        window: &mut Window,
16956        cx: &mut Context<Editor>,
16957    ) {
16958        let row = if direction == Direction::Next {
16959            self.hunk_after_position(snapshot, position)
16960                .map(|hunk| hunk.row_range.start)
16961        } else {
16962            self.hunk_before_position(snapshot, position)
16963        };
16964
16965        if let Some(row) = row {
16966            let destination = Point::new(row.0, 0);
16967            let autoscroll = Autoscroll::center();
16968
16969            self.unfold_ranges(&[destination..destination], false, false, cx);
16970            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16971                s.select_ranges([destination..destination]);
16972            });
16973        }
16974    }
16975
16976    fn hunk_after_position(
16977        &mut self,
16978        snapshot: &EditorSnapshot,
16979        position: Point,
16980    ) -> Option<MultiBufferDiffHunk> {
16981        snapshot
16982            .buffer_snapshot()
16983            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16984            .find(|hunk| hunk.row_range.start.0 > position.row)
16985            .or_else(|| {
16986                snapshot
16987                    .buffer_snapshot()
16988                    .diff_hunks_in_range(Point::zero()..position)
16989                    .find(|hunk| hunk.row_range.end.0 < position.row)
16990            })
16991    }
16992
16993    fn go_to_prev_hunk(
16994        &mut self,
16995        _: &GoToPreviousHunk,
16996        window: &mut Window,
16997        cx: &mut Context<Self>,
16998    ) {
16999        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17000        let snapshot = self.snapshot(window, cx);
17001        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
17002        self.go_to_hunk_before_or_after_position(
17003            &snapshot,
17004            selection.head(),
17005            Direction::Prev,
17006            window,
17007            cx,
17008        );
17009    }
17010
17011    fn hunk_before_position(
17012        &mut self,
17013        snapshot: &EditorSnapshot,
17014        position: Point,
17015    ) -> Option<MultiBufferRow> {
17016        snapshot
17017            .buffer_snapshot()
17018            .diff_hunk_before(position)
17019            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
17020    }
17021
17022    fn go_to_next_change(
17023        &mut self,
17024        _: &GoToNextChange,
17025        window: &mut Window,
17026        cx: &mut Context<Self>,
17027    ) {
17028        if let Some(selections) = self
17029            .change_list
17030            .next_change(1, Direction::Next)
17031            .map(|s| s.to_vec())
17032        {
17033            self.change_selections(Default::default(), window, cx, |s| {
17034                let map = s.display_snapshot();
17035                s.select_display_ranges(selections.iter().map(|a| {
17036                    let point = a.to_display_point(&map);
17037                    point..point
17038                }))
17039            })
17040        }
17041    }
17042
17043    fn go_to_previous_change(
17044        &mut self,
17045        _: &GoToPreviousChange,
17046        window: &mut Window,
17047        cx: &mut Context<Self>,
17048    ) {
17049        if let Some(selections) = self
17050            .change_list
17051            .next_change(1, Direction::Prev)
17052            .map(|s| s.to_vec())
17053        {
17054            self.change_selections(Default::default(), window, cx, |s| {
17055                let map = s.display_snapshot();
17056                s.select_display_ranges(selections.iter().map(|a| {
17057                    let point = a.to_display_point(&map);
17058                    point..point
17059                }))
17060            })
17061        }
17062    }
17063
17064    pub fn go_to_next_document_highlight(
17065        &mut self,
17066        _: &GoToNextDocumentHighlight,
17067        window: &mut Window,
17068        cx: &mut Context<Self>,
17069    ) {
17070        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
17071    }
17072
17073    pub fn go_to_prev_document_highlight(
17074        &mut self,
17075        _: &GoToPreviousDocumentHighlight,
17076        window: &mut Window,
17077        cx: &mut Context<Self>,
17078    ) {
17079        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17080    }
17081
17082    pub fn go_to_document_highlight_before_or_after_position(
17083        &mut self,
17084        direction: Direction,
17085        window: &mut Window,
17086        cx: &mut Context<Editor>,
17087    ) {
17088        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17089        let snapshot = self.snapshot(window, cx);
17090        let buffer = &snapshot.buffer_snapshot();
17091        let position = self
17092            .selections
17093            .newest::<Point>(&snapshot.display_snapshot)
17094            .head();
17095        let anchor_position = buffer.anchor_after(position);
17096
17097        // Get all document highlights (both read and write)
17098        let mut all_highlights = Vec::new();
17099
17100        if let Some((_, read_highlights)) = self
17101            .background_highlights
17102            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
17103        {
17104            all_highlights.extend(read_highlights.iter());
17105        }
17106
17107        if let Some((_, write_highlights)) = self
17108            .background_highlights
17109            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
17110        {
17111            all_highlights.extend(write_highlights.iter());
17112        }
17113
17114        if all_highlights.is_empty() {
17115            return;
17116        }
17117
17118        // Sort highlights by position
17119        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17120
17121        let target_highlight = match direction {
17122            Direction::Next => {
17123                // Find the first highlight after the current position
17124                all_highlights
17125                    .iter()
17126                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17127            }
17128            Direction::Prev => {
17129                // Find the last highlight before the current position
17130                all_highlights
17131                    .iter()
17132                    .rev()
17133                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17134            }
17135        };
17136
17137        if let Some(highlight) = target_highlight {
17138            let destination = highlight.start.to_point(buffer);
17139            let autoscroll = Autoscroll::center();
17140
17141            self.unfold_ranges(&[destination..destination], false, false, cx);
17142            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17143                s.select_ranges([destination..destination]);
17144            });
17145        }
17146    }
17147
17148    fn go_to_line<T: 'static>(
17149        &mut self,
17150        position: Anchor,
17151        highlight_color: Option<Hsla>,
17152        window: &mut Window,
17153        cx: &mut Context<Self>,
17154    ) {
17155        let snapshot = self.snapshot(window, cx).display_snapshot;
17156        let position = position.to_point(&snapshot.buffer_snapshot());
17157        let start = snapshot
17158            .buffer_snapshot()
17159            .clip_point(Point::new(position.row, 0), Bias::Left);
17160        let end = start + Point::new(1, 0);
17161        let start = snapshot.buffer_snapshot().anchor_before(start);
17162        let end = snapshot.buffer_snapshot().anchor_before(end);
17163
17164        self.highlight_rows::<T>(
17165            start..end,
17166            highlight_color
17167                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17168            Default::default(),
17169            cx,
17170        );
17171
17172        if self.buffer.read(cx).is_singleton() {
17173            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17174        }
17175    }
17176
17177    pub fn go_to_definition(
17178        &mut self,
17179        _: &GoToDefinition,
17180        window: &mut Window,
17181        cx: &mut Context<Self>,
17182    ) -> Task<Result<Navigated>> {
17183        let definition =
17184            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17185        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17186        cx.spawn_in(window, async move |editor, cx| {
17187            if definition.await? == Navigated::Yes {
17188                return Ok(Navigated::Yes);
17189            }
17190            match fallback_strategy {
17191                GoToDefinitionFallback::None => Ok(Navigated::No),
17192                GoToDefinitionFallback::FindAllReferences => {
17193                    match editor.update_in(cx, |editor, window, cx| {
17194                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17195                    })? {
17196                        Some(references) => references.await,
17197                        None => Ok(Navigated::No),
17198                    }
17199                }
17200            }
17201        })
17202    }
17203
17204    pub fn go_to_declaration(
17205        &mut self,
17206        _: &GoToDeclaration,
17207        window: &mut Window,
17208        cx: &mut Context<Self>,
17209    ) -> Task<Result<Navigated>> {
17210        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17211    }
17212
17213    pub fn go_to_declaration_split(
17214        &mut self,
17215        _: &GoToDeclaration,
17216        window: &mut Window,
17217        cx: &mut Context<Self>,
17218    ) -> Task<Result<Navigated>> {
17219        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17220    }
17221
17222    pub fn go_to_implementation(
17223        &mut self,
17224        _: &GoToImplementation,
17225        window: &mut Window,
17226        cx: &mut Context<Self>,
17227    ) -> Task<Result<Navigated>> {
17228        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17229    }
17230
17231    pub fn go_to_implementation_split(
17232        &mut self,
17233        _: &GoToImplementationSplit,
17234        window: &mut Window,
17235        cx: &mut Context<Self>,
17236    ) -> Task<Result<Navigated>> {
17237        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17238    }
17239
17240    pub fn go_to_type_definition(
17241        &mut self,
17242        _: &GoToTypeDefinition,
17243        window: &mut Window,
17244        cx: &mut Context<Self>,
17245    ) -> Task<Result<Navigated>> {
17246        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17247    }
17248
17249    pub fn go_to_definition_split(
17250        &mut self,
17251        _: &GoToDefinitionSplit,
17252        window: &mut Window,
17253        cx: &mut Context<Self>,
17254    ) -> Task<Result<Navigated>> {
17255        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17256    }
17257
17258    pub fn go_to_type_definition_split(
17259        &mut self,
17260        _: &GoToTypeDefinitionSplit,
17261        window: &mut Window,
17262        cx: &mut Context<Self>,
17263    ) -> Task<Result<Navigated>> {
17264        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17265    }
17266
17267    fn go_to_definition_of_kind(
17268        &mut self,
17269        kind: GotoDefinitionKind,
17270        split: bool,
17271        window: &mut Window,
17272        cx: &mut Context<Self>,
17273    ) -> Task<Result<Navigated>> {
17274        let Some(provider) = self.semantics_provider.clone() else {
17275            return Task::ready(Ok(Navigated::No));
17276        };
17277        let head = self
17278            .selections
17279            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17280            .head();
17281        let buffer = self.buffer.read(cx);
17282        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17283            return Task::ready(Ok(Navigated::No));
17284        };
17285        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17286            return Task::ready(Ok(Navigated::No));
17287        };
17288
17289        cx.spawn_in(window, async move |editor, cx| {
17290            let Some(definitions) = definitions.await? else {
17291                return Ok(Navigated::No);
17292            };
17293            let navigated = editor
17294                .update_in(cx, |editor, window, cx| {
17295                    editor.navigate_to_hover_links(
17296                        Some(kind),
17297                        definitions
17298                            .into_iter()
17299                            .filter(|location| {
17300                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17301                            })
17302                            .map(HoverLink::Text)
17303                            .collect::<Vec<_>>(),
17304                        split,
17305                        window,
17306                        cx,
17307                    )
17308                })?
17309                .await?;
17310            anyhow::Ok(navigated)
17311        })
17312    }
17313
17314    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17315        let selection = self.selections.newest_anchor();
17316        let head = selection.head();
17317        let tail = selection.tail();
17318
17319        let Some((buffer, start_position)) =
17320            self.buffer.read(cx).text_anchor_for_position(head, cx)
17321        else {
17322            return;
17323        };
17324
17325        let end_position = if head != tail {
17326            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17327                return;
17328            };
17329            Some(pos)
17330        } else {
17331            None
17332        };
17333
17334        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17335            let url = if let Some(end_pos) = end_position {
17336                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17337            } else {
17338                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17339            };
17340
17341            if let Some(url) = url {
17342                cx.update(|window, cx| {
17343                    if parse_zed_link(&url, cx).is_some() {
17344                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17345                    } else {
17346                        cx.open_url(&url);
17347                    }
17348                })?;
17349            }
17350
17351            anyhow::Ok(())
17352        });
17353
17354        url_finder.detach();
17355    }
17356
17357    pub fn open_selected_filename(
17358        &mut self,
17359        _: &OpenSelectedFilename,
17360        window: &mut Window,
17361        cx: &mut Context<Self>,
17362    ) {
17363        let Some(workspace) = self.workspace() else {
17364            return;
17365        };
17366
17367        let position = self.selections.newest_anchor().head();
17368
17369        let Some((buffer, buffer_position)) =
17370            self.buffer.read(cx).text_anchor_for_position(position, cx)
17371        else {
17372            return;
17373        };
17374
17375        let project = self.project.clone();
17376
17377        cx.spawn_in(window, async move |_, cx| {
17378            let result = find_file(&buffer, project, buffer_position, cx).await;
17379
17380            if let Some((_, path)) = result {
17381                workspace
17382                    .update_in(cx, |workspace, window, cx| {
17383                        workspace.open_resolved_path(path, window, cx)
17384                    })?
17385                    .await?;
17386            }
17387            anyhow::Ok(())
17388        })
17389        .detach();
17390    }
17391
17392    pub(crate) fn navigate_to_hover_links(
17393        &mut self,
17394        kind: Option<GotoDefinitionKind>,
17395        definitions: Vec<HoverLink>,
17396        split: bool,
17397        window: &mut Window,
17398        cx: &mut Context<Editor>,
17399    ) -> Task<Result<Navigated>> {
17400        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17401        let mut first_url_or_file = None;
17402        let definitions: Vec<_> = definitions
17403            .into_iter()
17404            .filter_map(|def| match def {
17405                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17406                HoverLink::InlayHint(lsp_location, server_id) => {
17407                    let computation =
17408                        self.compute_target_location(lsp_location, server_id, window, cx);
17409                    Some(cx.background_spawn(computation))
17410                }
17411                HoverLink::Url(url) => {
17412                    first_url_or_file = Some(Either::Left(url));
17413                    None
17414                }
17415                HoverLink::File(path) => {
17416                    first_url_or_file = Some(Either::Right(path));
17417                    None
17418                }
17419            })
17420            .collect();
17421
17422        let workspace = self.workspace();
17423
17424        cx.spawn_in(window, async move |editor, cx| {
17425            let locations: Vec<Location> = future::join_all(definitions)
17426                .await
17427                .into_iter()
17428                .filter_map(|location| location.transpose())
17429                .collect::<Result<_>>()
17430                .context("location tasks")?;
17431            let mut locations = cx.update(|_, cx| {
17432                locations
17433                    .into_iter()
17434                    .map(|location| {
17435                        let buffer = location.buffer.read(cx);
17436                        (location.buffer, location.range.to_point(buffer))
17437                    })
17438                    .into_group_map()
17439            })?;
17440            let mut num_locations = 0;
17441            for ranges in locations.values_mut() {
17442                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17443                ranges.dedup();
17444                num_locations += ranges.len();
17445            }
17446
17447            if num_locations > 1 {
17448                let tab_kind = match kind {
17449                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17450                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17451                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17452                    Some(GotoDefinitionKind::Type) => "Types",
17453                };
17454                let title = editor
17455                    .update_in(cx, |_, _, cx| {
17456                        let target = locations
17457                            .iter()
17458                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17459                            .map(|(buffer, location)| {
17460                                buffer
17461                                    .read(cx)
17462                                    .text_for_range(location.clone())
17463                                    .collect::<String>()
17464                            })
17465                            .filter(|text| !text.contains('\n'))
17466                            .unique()
17467                            .take(3)
17468                            .join(", ");
17469                        if target.is_empty() {
17470                            tab_kind.to_owned()
17471                        } else {
17472                            format!("{tab_kind} for {target}")
17473                        }
17474                    })
17475                    .context("buffer title")?;
17476
17477                let Some(workspace) = workspace else {
17478                    return Ok(Navigated::No);
17479                };
17480
17481                let opened = workspace
17482                    .update_in(cx, |workspace, window, cx| {
17483                        let allow_preview = PreviewTabsSettings::get_global(cx)
17484                            .enable_preview_multibuffer_from_code_navigation;
17485                        Self::open_locations_in_multibuffer(
17486                            workspace,
17487                            locations,
17488                            title,
17489                            split,
17490                            allow_preview,
17491                            MultibufferSelectionMode::First,
17492                            window,
17493                            cx,
17494                        )
17495                    })
17496                    .is_ok();
17497
17498                anyhow::Ok(Navigated::from_bool(opened))
17499            } else if num_locations == 0 {
17500                // If there is one url or file, open it directly
17501                match first_url_or_file {
17502                    Some(Either::Left(url)) => {
17503                        cx.update(|window, cx| {
17504                            if parse_zed_link(&url, cx).is_some() {
17505                                window
17506                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17507                            } else {
17508                                cx.open_url(&url);
17509                            }
17510                        })?;
17511                        Ok(Navigated::Yes)
17512                    }
17513                    Some(Either::Right(path)) => {
17514                        // TODO(andrew): respect preview tab settings
17515                        //               `enable_keep_preview_on_code_navigation` and
17516                        //               `enable_preview_file_from_code_navigation`
17517                        let Some(workspace) = workspace else {
17518                            return Ok(Navigated::No);
17519                        };
17520                        workspace
17521                            .update_in(cx, |workspace, window, cx| {
17522                                workspace.open_resolved_path(path, window, cx)
17523                            })?
17524                            .await?;
17525                        Ok(Navigated::Yes)
17526                    }
17527                    None => Ok(Navigated::No),
17528                }
17529            } else {
17530                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17531                let target_range = target_ranges.first().unwrap().clone();
17532
17533                editor.update_in(cx, |editor, window, cx| {
17534                    let range = target_range.to_point(target_buffer.read(cx));
17535                    let range = editor.range_for_match(&range);
17536                    let range = collapse_multiline_range(range);
17537
17538                    if !split
17539                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17540                    {
17541                        editor.go_to_singleton_buffer_range(range, window, cx);
17542                    } else {
17543                        let Some(workspace) = workspace else {
17544                            return Navigated::No;
17545                        };
17546                        let pane = workspace.read(cx).active_pane().clone();
17547                        window.defer(cx, move |window, cx| {
17548                            let target_editor: Entity<Self> =
17549                                workspace.update(cx, |workspace, cx| {
17550                                    let pane = if split {
17551                                        workspace.adjacent_pane(window, cx)
17552                                    } else {
17553                                        workspace.active_pane().clone()
17554                                    };
17555
17556                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17557                                    let keep_old_preview = preview_tabs_settings
17558                                        .enable_keep_preview_on_code_navigation;
17559                                    let allow_new_preview = preview_tabs_settings
17560                                        .enable_preview_file_from_code_navigation;
17561
17562                                    workspace.open_project_item(
17563                                        pane,
17564                                        target_buffer.clone(),
17565                                        true,
17566                                        true,
17567                                        keep_old_preview,
17568                                        allow_new_preview,
17569                                        window,
17570                                        cx,
17571                                    )
17572                                });
17573                            target_editor.update(cx, |target_editor, cx| {
17574                                // When selecting a definition in a different buffer, disable the nav history
17575                                // to avoid creating a history entry at the previous cursor location.
17576                                pane.update(cx, |pane, _| pane.disable_history());
17577                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17578                                pane.update(cx, |pane, _| pane.enable_history());
17579                            });
17580                        });
17581                    }
17582                    Navigated::Yes
17583                })
17584            }
17585        })
17586    }
17587
17588    fn compute_target_location(
17589        &self,
17590        lsp_location: lsp::Location,
17591        server_id: LanguageServerId,
17592        window: &mut Window,
17593        cx: &mut Context<Self>,
17594    ) -> Task<anyhow::Result<Option<Location>>> {
17595        let Some(project) = self.project.clone() else {
17596            return Task::ready(Ok(None));
17597        };
17598
17599        cx.spawn_in(window, async move |editor, cx| {
17600            let location_task = editor.update(cx, |_, cx| {
17601                project.update(cx, |project, cx| {
17602                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17603                })
17604            })?;
17605            let location = Some({
17606                let target_buffer_handle = location_task.await.context("open local buffer")?;
17607                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17608                    let target_start = target_buffer
17609                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17610                    let target_end = target_buffer
17611                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17612                    target_buffer.anchor_after(target_start)
17613                        ..target_buffer.anchor_before(target_end)
17614                })?;
17615                Location {
17616                    buffer: target_buffer_handle,
17617                    range,
17618                }
17619            });
17620            Ok(location)
17621        })
17622    }
17623
17624    fn go_to_next_reference(
17625        &mut self,
17626        _: &GoToNextReference,
17627        window: &mut Window,
17628        cx: &mut Context<Self>,
17629    ) {
17630        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17631        if let Some(task) = task {
17632            task.detach();
17633        };
17634    }
17635
17636    fn go_to_prev_reference(
17637        &mut self,
17638        _: &GoToPreviousReference,
17639        window: &mut Window,
17640        cx: &mut Context<Self>,
17641    ) {
17642        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17643        if let Some(task) = task {
17644            task.detach();
17645        };
17646    }
17647
17648    pub fn go_to_reference_before_or_after_position(
17649        &mut self,
17650        direction: Direction,
17651        count: usize,
17652        window: &mut Window,
17653        cx: &mut Context<Self>,
17654    ) -> Option<Task<Result<()>>> {
17655        let selection = self.selections.newest_anchor();
17656        let head = selection.head();
17657
17658        let multi_buffer = self.buffer.read(cx);
17659
17660        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17661        let workspace = self.workspace()?;
17662        let project = workspace.read(cx).project().clone();
17663        let references =
17664            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17665        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17666            let Some(locations) = references.await? else {
17667                return Ok(());
17668            };
17669
17670            if locations.is_empty() {
17671                // totally normal - the cursor may be on something which is not
17672                // a symbol (e.g. a keyword)
17673                log::info!("no references found under cursor");
17674                return Ok(());
17675            }
17676
17677            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17678
17679            let (locations, current_location_index) =
17680                multi_buffer.update(cx, |multi_buffer, cx| {
17681                    let mut locations = locations
17682                        .into_iter()
17683                        .filter_map(|loc| {
17684                            let start = multi_buffer.buffer_anchor_to_anchor(
17685                                &loc.buffer,
17686                                loc.range.start,
17687                                cx,
17688                            )?;
17689                            let end = multi_buffer.buffer_anchor_to_anchor(
17690                                &loc.buffer,
17691                                loc.range.end,
17692                                cx,
17693                            )?;
17694                            Some(start..end)
17695                        })
17696                        .collect::<Vec<_>>();
17697
17698                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17699                    // There is an O(n) implementation, but given this list will be
17700                    // small (usually <100 items), the extra O(log(n)) factor isn't
17701                    // worth the (surprisingly large amount of) extra complexity.
17702                    locations
17703                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17704
17705                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17706
17707                    let current_location_index = locations.iter().position(|loc| {
17708                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17709                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17710                    });
17711
17712                    (locations, current_location_index)
17713                })?;
17714
17715            let Some(current_location_index) = current_location_index else {
17716                // This indicates something has gone wrong, because we already
17717                // handle the "no references" case above
17718                log::error!(
17719                    "failed to find current reference under cursor. Total references: {}",
17720                    locations.len()
17721                );
17722                return Ok(());
17723            };
17724
17725            let destination_location_index = match direction {
17726                Direction::Next => (current_location_index + count) % locations.len(),
17727                Direction::Prev => {
17728                    (current_location_index + locations.len() - count % locations.len())
17729                        % locations.len()
17730                }
17731            };
17732
17733            // TODO(cameron): is this needed?
17734            // the thinking is to avoid "jumping to the current location" (avoid
17735            // polluting "jumplist" in vim terms)
17736            if current_location_index == destination_location_index {
17737                return Ok(());
17738            }
17739
17740            let Range { start, end } = locations[destination_location_index];
17741
17742            editor.update_in(cx, |editor, window, cx| {
17743                let effects = SelectionEffects::default();
17744
17745                editor.unfold_ranges(&[start..end], false, false, cx);
17746                editor.change_selections(effects, window, cx, |s| {
17747                    s.select_ranges([start..start]);
17748                });
17749            })?;
17750
17751            Ok(())
17752        }))
17753    }
17754
17755    pub fn find_all_references(
17756        &mut self,
17757        action: &FindAllReferences,
17758        window: &mut Window,
17759        cx: &mut Context<Self>,
17760    ) -> Option<Task<Result<Navigated>>> {
17761        let always_open_multibuffer = action.always_open_multibuffer;
17762        let selection = self.selections.newest_anchor();
17763        let multi_buffer = self.buffer.read(cx);
17764        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17765        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
17766        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
17767        let head = selection_offset.head();
17768
17769        let head_anchor = multi_buffer_snapshot.anchor_at(
17770            head,
17771            if head < selection_offset.tail() {
17772                Bias::Right
17773            } else {
17774                Bias::Left
17775            },
17776        );
17777
17778        match self
17779            .find_all_references_task_sources
17780            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17781        {
17782            Ok(_) => {
17783                log::info!(
17784                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17785                );
17786                return None;
17787            }
17788            Err(i) => {
17789                self.find_all_references_task_sources.insert(i, head_anchor);
17790            }
17791        }
17792
17793        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17794        let workspace = self.workspace()?;
17795        let project = workspace.read(cx).project().clone();
17796        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17797        Some(cx.spawn_in(window, async move |editor, cx| {
17798            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17799                if let Ok(i) = editor
17800                    .find_all_references_task_sources
17801                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17802                {
17803                    editor.find_all_references_task_sources.remove(i);
17804                }
17805            });
17806
17807            let Some(locations) = references.await? else {
17808                return anyhow::Ok(Navigated::No);
17809            };
17810            let mut locations = cx.update(|_, cx| {
17811                locations
17812                    .into_iter()
17813                    .map(|location| {
17814                        let buffer = location.buffer.read(cx);
17815                        (location.buffer, location.range.to_point(buffer))
17816                    })
17817                    // if special-casing the single-match case, remove ranges
17818                    // that intersect current selection
17819                    .filter(|(location_buffer, location)| {
17820                        if always_open_multibuffer || &buffer != location_buffer {
17821                            return true;
17822                        }
17823
17824                        !location.contains_inclusive(&selection_point.range())
17825                    })
17826                    .into_group_map()
17827            })?;
17828            if locations.is_empty() {
17829                return anyhow::Ok(Navigated::No);
17830            }
17831            for ranges in locations.values_mut() {
17832                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17833                ranges.dedup();
17834            }
17835            let mut num_locations = 0;
17836            for ranges in locations.values_mut() {
17837                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17838                ranges.dedup();
17839                num_locations += ranges.len();
17840            }
17841
17842            if num_locations == 1 && !always_open_multibuffer {
17843                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17844                let target_range = target_ranges.first().unwrap().clone();
17845
17846                return editor.update_in(cx, |editor, window, cx| {
17847                    let range = target_range.to_point(target_buffer.read(cx));
17848                    let range = editor.range_for_match(&range);
17849                    let range = range.start..range.start;
17850
17851                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
17852                        editor.go_to_singleton_buffer_range(range, window, cx);
17853                    } else {
17854                        let pane = workspace.read(cx).active_pane().clone();
17855                        window.defer(cx, move |window, cx| {
17856                            let target_editor: Entity<Self> =
17857                                workspace.update(cx, |workspace, cx| {
17858                                    let pane = workspace.active_pane().clone();
17859
17860                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17861                                    let keep_old_preview = preview_tabs_settings
17862                                        .enable_keep_preview_on_code_navigation;
17863                                    let allow_new_preview = preview_tabs_settings
17864                                        .enable_preview_file_from_code_navigation;
17865
17866                                    workspace.open_project_item(
17867                                        pane,
17868                                        target_buffer.clone(),
17869                                        true,
17870                                        true,
17871                                        keep_old_preview,
17872                                        allow_new_preview,
17873                                        window,
17874                                        cx,
17875                                    )
17876                                });
17877                            target_editor.update(cx, |target_editor, cx| {
17878                                // When selecting a definition in a different buffer, disable the nav history
17879                                // to avoid creating a history entry at the previous cursor location.
17880                                pane.update(cx, |pane, _| pane.disable_history());
17881                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17882                                pane.update(cx, |pane, _| pane.enable_history());
17883                            });
17884                        });
17885                    }
17886                    Navigated::No
17887                });
17888            }
17889
17890            workspace.update_in(cx, |workspace, window, cx| {
17891                let target = locations
17892                    .iter()
17893                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17894                    .map(|(buffer, location)| {
17895                        buffer
17896                            .read(cx)
17897                            .text_for_range(location.clone())
17898                            .collect::<String>()
17899                    })
17900                    .filter(|text| !text.contains('\n'))
17901                    .unique()
17902                    .take(3)
17903                    .join(", ");
17904                let title = if target.is_empty() {
17905                    "References".to_owned()
17906                } else {
17907                    format!("References to {target}")
17908                };
17909                let allow_preview = PreviewTabsSettings::get_global(cx)
17910                    .enable_preview_multibuffer_from_code_navigation;
17911                Self::open_locations_in_multibuffer(
17912                    workspace,
17913                    locations,
17914                    title,
17915                    false,
17916                    allow_preview,
17917                    MultibufferSelectionMode::First,
17918                    window,
17919                    cx,
17920                );
17921                Navigated::Yes
17922            })
17923        }))
17924    }
17925
17926    /// Opens a multibuffer with the given project locations in it.
17927    pub fn open_locations_in_multibuffer(
17928        workspace: &mut Workspace,
17929        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17930        title: String,
17931        split: bool,
17932        allow_preview: bool,
17933        multibuffer_selection_mode: MultibufferSelectionMode,
17934        window: &mut Window,
17935        cx: &mut Context<Workspace>,
17936    ) {
17937        if locations.is_empty() {
17938            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17939            return;
17940        }
17941
17942        let capability = workspace.project().read(cx).capability();
17943        let mut ranges = <Vec<Range<Anchor>>>::new();
17944
17945        // a key to find existing multibuffer editors with the same set of locations
17946        // to prevent us from opening more and more multibuffer tabs for searches and the like
17947        let mut key = (title.clone(), vec![]);
17948        let excerpt_buffer = cx.new(|cx| {
17949            let key = &mut key.1;
17950            let mut multibuffer = MultiBuffer::new(capability);
17951            for (buffer, mut ranges_for_buffer) in locations {
17952                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17953                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17954                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17955                    PathKey::for_buffer(&buffer, cx),
17956                    buffer.clone(),
17957                    ranges_for_buffer,
17958                    multibuffer_context_lines(cx),
17959                    cx,
17960                );
17961                ranges.extend(new_ranges)
17962            }
17963
17964            multibuffer.with_title(title)
17965        });
17966        let existing = workspace.active_pane().update(cx, |pane, cx| {
17967            pane.items()
17968                .filter_map(|item| item.downcast::<Editor>())
17969                .find(|editor| {
17970                    editor
17971                        .read(cx)
17972                        .lookup_key
17973                        .as_ref()
17974                        .and_then(|it| {
17975                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17976                        })
17977                        .is_some_and(|it| *it == key)
17978                })
17979        });
17980        let was_existing = existing.is_some();
17981        let editor = existing.unwrap_or_else(|| {
17982            cx.new(|cx| {
17983                let mut editor = Editor::for_multibuffer(
17984                    excerpt_buffer,
17985                    Some(workspace.project().clone()),
17986                    window,
17987                    cx,
17988                );
17989                editor.lookup_key = Some(Box::new(key));
17990                editor
17991            })
17992        });
17993        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17994            MultibufferSelectionMode::First => {
17995                if let Some(first_range) = ranges.first() {
17996                    editor.change_selections(
17997                        SelectionEffects::no_scroll(),
17998                        window,
17999                        cx,
18000                        |selections| {
18001                            selections.clear_disjoint();
18002                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
18003                        },
18004                    );
18005                }
18006                editor.highlight_background::<Self>(
18007                    &ranges,
18008                    |_, theme| theme.colors().editor_highlighted_line_background,
18009                    cx,
18010                );
18011            }
18012            MultibufferSelectionMode::All => {
18013                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
18014                    selections.clear_disjoint();
18015                    selections.select_anchor_ranges(ranges);
18016                });
18017            }
18018        });
18019
18020        let item = Box::new(editor);
18021
18022        let pane = if split {
18023            workspace.adjacent_pane(window, cx)
18024        } else {
18025            workspace.active_pane().clone()
18026        };
18027        let activate_pane = split;
18028
18029        let mut destination_index = None;
18030        pane.update(cx, |pane, cx| {
18031            if allow_preview && !was_existing {
18032                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
18033            }
18034            if was_existing && !allow_preview {
18035                pane.unpreview_item_if_preview(item.item_id());
18036            }
18037            pane.add_item(item, activate_pane, true, destination_index, window, cx);
18038        });
18039    }
18040
18041    pub fn rename(
18042        &mut self,
18043        _: &Rename,
18044        window: &mut Window,
18045        cx: &mut Context<Self>,
18046    ) -> Option<Task<Result<()>>> {
18047        use language::ToOffset as _;
18048
18049        let provider = self.semantics_provider.clone()?;
18050        let selection = self.selections.newest_anchor().clone();
18051        let (cursor_buffer, cursor_buffer_position) = self
18052            .buffer
18053            .read(cx)
18054            .text_anchor_for_position(selection.head(), cx)?;
18055        let (tail_buffer, cursor_buffer_position_end) = self
18056            .buffer
18057            .read(cx)
18058            .text_anchor_for_position(selection.tail(), cx)?;
18059        if tail_buffer != cursor_buffer {
18060            return None;
18061        }
18062
18063        let snapshot = cursor_buffer.read(cx).snapshot();
18064        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
18065        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
18066        let prepare_rename = provider
18067            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
18068            .unwrap_or_else(|| Task::ready(Ok(None)));
18069        drop(snapshot);
18070
18071        Some(cx.spawn_in(window, async move |this, cx| {
18072            let rename_range = if let Some(range) = prepare_rename.await? {
18073                Some(range)
18074            } else {
18075                this.update(cx, |this, cx| {
18076                    let buffer = this.buffer.read(cx).snapshot(cx);
18077                    let mut buffer_highlights = this
18078                        .document_highlights_for_position(selection.head(), &buffer)
18079                        .filter(|highlight| {
18080                            highlight.start.excerpt_id == selection.head().excerpt_id
18081                                && highlight.end.excerpt_id == selection.head().excerpt_id
18082                        });
18083                    buffer_highlights
18084                        .next()
18085                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
18086                })?
18087            };
18088            if let Some(rename_range) = rename_range {
18089                this.update_in(cx, |this, window, cx| {
18090                    let snapshot = cursor_buffer.read(cx).snapshot();
18091                    let rename_buffer_range = rename_range.to_offset(&snapshot);
18092                    let cursor_offset_in_rename_range =
18093                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
18094                    let cursor_offset_in_rename_range_end =
18095                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
18096
18097                    this.take_rename(false, window, cx);
18098                    let buffer = this.buffer.read(cx).read(cx);
18099                    let cursor_offset = selection.head().to_offset(&buffer);
18100                    let rename_start =
18101                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
18102                    let rename_end = rename_start + rename_buffer_range.len();
18103                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
18104                    let mut old_highlight_id = None;
18105                    let old_name: Arc<str> = buffer
18106                        .chunks(rename_start..rename_end, true)
18107                        .map(|chunk| {
18108                            if old_highlight_id.is_none() {
18109                                old_highlight_id = chunk.syntax_highlight_id;
18110                            }
18111                            chunk.text
18112                        })
18113                        .collect::<String>()
18114                        .into();
18115
18116                    drop(buffer);
18117
18118                    // Position the selection in the rename editor so that it matches the current selection.
18119                    this.show_local_selections = false;
18120                    let rename_editor = cx.new(|cx| {
18121                        let mut editor = Editor::single_line(window, cx);
18122                        editor.buffer.update(cx, |buffer, cx| {
18123                            buffer.edit(
18124                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18125                                None,
18126                                cx,
18127                            )
18128                        });
18129                        let cursor_offset_in_rename_range =
18130                            MultiBufferOffset(cursor_offset_in_rename_range);
18131                        let cursor_offset_in_rename_range_end =
18132                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18133                        let rename_selection_range = match cursor_offset_in_rename_range
18134                            .cmp(&cursor_offset_in_rename_range_end)
18135                        {
18136                            Ordering::Equal => {
18137                                editor.select_all(&SelectAll, window, cx);
18138                                return editor;
18139                            }
18140                            Ordering::Less => {
18141                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18142                            }
18143                            Ordering::Greater => {
18144                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18145                            }
18146                        };
18147                        if rename_selection_range.end.0 > old_name.len() {
18148                            editor.select_all(&SelectAll, window, cx);
18149                        } else {
18150                            editor.change_selections(Default::default(), window, cx, |s| {
18151                                s.select_ranges([rename_selection_range]);
18152                            });
18153                        }
18154                        editor
18155                    });
18156                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18157                        if e == &EditorEvent::Focused {
18158                            cx.emit(EditorEvent::FocusedIn)
18159                        }
18160                    })
18161                    .detach();
18162
18163                    let write_highlights =
18164                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18165                    let read_highlights =
18166                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18167                    let ranges = write_highlights
18168                        .iter()
18169                        .flat_map(|(_, ranges)| ranges.iter())
18170                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18171                        .cloned()
18172                        .collect();
18173
18174                    this.highlight_text::<Rename>(
18175                        ranges,
18176                        HighlightStyle {
18177                            fade_out: Some(0.6),
18178                            ..Default::default()
18179                        },
18180                        cx,
18181                    );
18182                    let rename_focus_handle = rename_editor.focus_handle(cx);
18183                    window.focus(&rename_focus_handle, cx);
18184                    let block_id = this.insert_blocks(
18185                        [BlockProperties {
18186                            style: BlockStyle::Flex,
18187                            placement: BlockPlacement::Below(range.start),
18188                            height: Some(1),
18189                            render: Arc::new({
18190                                let rename_editor = rename_editor.clone();
18191                                move |cx: &mut BlockContext| {
18192                                    let mut text_style = cx.editor_style.text.clone();
18193                                    if let Some(highlight_style) = old_highlight_id
18194                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18195                                    {
18196                                        text_style = text_style.highlight(highlight_style);
18197                                    }
18198                                    div()
18199                                        .block_mouse_except_scroll()
18200                                        .pl(cx.anchor_x)
18201                                        .child(EditorElement::new(
18202                                            &rename_editor,
18203                                            EditorStyle {
18204                                                background: cx.theme().system().transparent,
18205                                                local_player: cx.editor_style.local_player,
18206                                                text: text_style,
18207                                                scrollbar_width: cx.editor_style.scrollbar_width,
18208                                                syntax: cx.editor_style.syntax.clone(),
18209                                                status: cx.editor_style.status.clone(),
18210                                                inlay_hints_style: HighlightStyle {
18211                                                    font_weight: Some(FontWeight::BOLD),
18212                                                    ..make_inlay_hints_style(cx.app)
18213                                                },
18214                                                edit_prediction_styles: make_suggestion_styles(
18215                                                    cx.app,
18216                                                ),
18217                                                ..EditorStyle::default()
18218                                            },
18219                                        ))
18220                                        .into_any_element()
18221                                }
18222                            }),
18223                            priority: 0,
18224                        }],
18225                        Some(Autoscroll::fit()),
18226                        cx,
18227                    )[0];
18228                    this.pending_rename = Some(RenameState {
18229                        range,
18230                        old_name,
18231                        editor: rename_editor,
18232                        block_id,
18233                    });
18234                })?;
18235            }
18236
18237            Ok(())
18238        }))
18239    }
18240
18241    pub fn confirm_rename(
18242        &mut self,
18243        _: &ConfirmRename,
18244        window: &mut Window,
18245        cx: &mut Context<Self>,
18246    ) -> Option<Task<Result<()>>> {
18247        let rename = self.take_rename(false, window, cx)?;
18248        let workspace = self.workspace()?.downgrade();
18249        let (buffer, start) = self
18250            .buffer
18251            .read(cx)
18252            .text_anchor_for_position(rename.range.start, cx)?;
18253        let (end_buffer, _) = self
18254            .buffer
18255            .read(cx)
18256            .text_anchor_for_position(rename.range.end, cx)?;
18257        if buffer != end_buffer {
18258            return None;
18259        }
18260
18261        let old_name = rename.old_name;
18262        let new_name = rename.editor.read(cx).text(cx);
18263
18264        let rename = self.semantics_provider.as_ref()?.perform_rename(
18265            &buffer,
18266            start,
18267            new_name.clone(),
18268            cx,
18269        )?;
18270
18271        Some(cx.spawn_in(window, async move |editor, cx| {
18272            let project_transaction = rename.await?;
18273            Self::open_project_transaction(
18274                &editor,
18275                workspace,
18276                project_transaction,
18277                format!("Rename: {}{}", old_name, new_name),
18278                cx,
18279            )
18280            .await?;
18281
18282            editor.update(cx, |editor, cx| {
18283                editor.refresh_document_highlights(cx);
18284            })?;
18285            Ok(())
18286        }))
18287    }
18288
18289    fn take_rename(
18290        &mut self,
18291        moving_cursor: bool,
18292        window: &mut Window,
18293        cx: &mut Context<Self>,
18294    ) -> Option<RenameState> {
18295        let rename = self.pending_rename.take()?;
18296        if rename.editor.focus_handle(cx).is_focused(window) {
18297            window.focus(&self.focus_handle, cx);
18298        }
18299
18300        self.remove_blocks(
18301            [rename.block_id].into_iter().collect(),
18302            Some(Autoscroll::fit()),
18303            cx,
18304        );
18305        self.clear_highlights::<Rename>(cx);
18306        self.show_local_selections = true;
18307
18308        if moving_cursor {
18309            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18310                editor
18311                    .selections
18312                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18313                    .head()
18314            });
18315
18316            // Update the selection to match the position of the selection inside
18317            // the rename editor.
18318            let snapshot = self.buffer.read(cx).read(cx);
18319            let rename_range = rename.range.to_offset(&snapshot);
18320            let cursor_in_editor = snapshot
18321                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18322                .min(rename_range.end);
18323            drop(snapshot);
18324
18325            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18326                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18327            });
18328        } else {
18329            self.refresh_document_highlights(cx);
18330        }
18331
18332        Some(rename)
18333    }
18334
18335    pub fn pending_rename(&self) -> Option<&RenameState> {
18336        self.pending_rename.as_ref()
18337    }
18338
18339    fn format(
18340        &mut self,
18341        _: &Format,
18342        window: &mut Window,
18343        cx: &mut Context<Self>,
18344    ) -> Option<Task<Result<()>>> {
18345        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18346
18347        let project = match &self.project {
18348            Some(project) => project.clone(),
18349            None => return None,
18350        };
18351
18352        Some(self.perform_format(
18353            project,
18354            FormatTrigger::Manual,
18355            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18356            window,
18357            cx,
18358        ))
18359    }
18360
18361    fn format_selections(
18362        &mut self,
18363        _: &FormatSelections,
18364        window: &mut Window,
18365        cx: &mut Context<Self>,
18366    ) -> Option<Task<Result<()>>> {
18367        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18368
18369        let project = match &self.project {
18370            Some(project) => project.clone(),
18371            None => return None,
18372        };
18373
18374        let ranges = self
18375            .selections
18376            .all_adjusted(&self.display_snapshot(cx))
18377            .into_iter()
18378            .map(|selection| selection.range())
18379            .collect_vec();
18380
18381        Some(self.perform_format(
18382            project,
18383            FormatTrigger::Manual,
18384            FormatTarget::Ranges(ranges),
18385            window,
18386            cx,
18387        ))
18388    }
18389
18390    fn perform_format(
18391        &mut self,
18392        project: Entity<Project>,
18393        trigger: FormatTrigger,
18394        target: FormatTarget,
18395        window: &mut Window,
18396        cx: &mut Context<Self>,
18397    ) -> Task<Result<()>> {
18398        let buffer = self.buffer.clone();
18399        let (buffers, target) = match target {
18400            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18401            FormatTarget::Ranges(selection_ranges) => {
18402                let multi_buffer = buffer.read(cx);
18403                let snapshot = multi_buffer.read(cx);
18404                let mut buffers = HashSet::default();
18405                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18406                    BTreeMap::new();
18407                for selection_range in selection_ranges {
18408                    for (buffer, buffer_range, _) in
18409                        snapshot.range_to_buffer_ranges(selection_range)
18410                    {
18411                        let buffer_id = buffer.remote_id();
18412                        let start = buffer.anchor_before(buffer_range.start);
18413                        let end = buffer.anchor_after(buffer_range.end);
18414                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18415                        buffer_id_to_ranges
18416                            .entry(buffer_id)
18417                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18418                            .or_insert_with(|| vec![start..end]);
18419                    }
18420                }
18421                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18422            }
18423        };
18424
18425        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18426        let selections_prev = transaction_id_prev
18427            .and_then(|transaction_id_prev| {
18428                // default to selections as they were after the last edit, if we have them,
18429                // instead of how they are now.
18430                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18431                // will take you back to where you made the last edit, instead of staying where you scrolled
18432                self.selection_history
18433                    .transaction(transaction_id_prev)
18434                    .map(|t| t.0.clone())
18435            })
18436            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18437
18438        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18439        let format = project.update(cx, |project, cx| {
18440            project.format(buffers, target, true, trigger, cx)
18441        });
18442
18443        cx.spawn_in(window, async move |editor, cx| {
18444            let transaction = futures::select_biased! {
18445                transaction = format.log_err().fuse() => transaction,
18446                () = timeout => {
18447                    log::warn!("timed out waiting for formatting");
18448                    None
18449                }
18450            };
18451
18452            buffer
18453                .update(cx, |buffer, cx| {
18454                    if let Some(transaction) = transaction
18455                        && !buffer.is_singleton()
18456                    {
18457                        buffer.push_transaction(&transaction.0, cx);
18458                    }
18459                    cx.notify();
18460                })
18461                .ok();
18462
18463            if let Some(transaction_id_now) =
18464                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
18465            {
18466                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18467                if has_new_transaction {
18468                    _ = editor.update(cx, |editor, _| {
18469                        editor
18470                            .selection_history
18471                            .insert_transaction(transaction_id_now, selections_prev);
18472                    });
18473                }
18474            }
18475
18476            Ok(())
18477        })
18478    }
18479
18480    fn organize_imports(
18481        &mut self,
18482        _: &OrganizeImports,
18483        window: &mut Window,
18484        cx: &mut Context<Self>,
18485    ) -> Option<Task<Result<()>>> {
18486        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18487        let project = match &self.project {
18488            Some(project) => project.clone(),
18489            None => return None,
18490        };
18491        Some(self.perform_code_action_kind(
18492            project,
18493            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18494            window,
18495            cx,
18496        ))
18497    }
18498
18499    fn perform_code_action_kind(
18500        &mut self,
18501        project: Entity<Project>,
18502        kind: CodeActionKind,
18503        window: &mut Window,
18504        cx: &mut Context<Self>,
18505    ) -> Task<Result<()>> {
18506        let buffer = self.buffer.clone();
18507        let buffers = buffer.read(cx).all_buffers();
18508        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18509        let apply_action = project.update(cx, |project, cx| {
18510            project.apply_code_action_kind(buffers, kind, true, cx)
18511        });
18512        cx.spawn_in(window, async move |_, cx| {
18513            let transaction = futures::select_biased! {
18514                () = timeout => {
18515                    log::warn!("timed out waiting for executing code action");
18516                    None
18517                }
18518                transaction = apply_action.log_err().fuse() => transaction,
18519            };
18520            buffer
18521                .update(cx, |buffer, cx| {
18522                    // check if we need this
18523                    if let Some(transaction) = transaction
18524                        && !buffer.is_singleton()
18525                    {
18526                        buffer.push_transaction(&transaction.0, cx);
18527                    }
18528                    cx.notify();
18529                })
18530                .ok();
18531            Ok(())
18532        })
18533    }
18534
18535    pub fn restart_language_server(
18536        &mut self,
18537        _: &RestartLanguageServer,
18538        _: &mut Window,
18539        cx: &mut Context<Self>,
18540    ) {
18541        if let Some(project) = self.project.clone() {
18542            self.buffer.update(cx, |multi_buffer, cx| {
18543                project.update(cx, |project, cx| {
18544                    project.restart_language_servers_for_buffers(
18545                        multi_buffer.all_buffers().into_iter().collect(),
18546                        HashSet::default(),
18547                        cx,
18548                    );
18549                });
18550            })
18551        }
18552    }
18553
18554    pub fn stop_language_server(
18555        &mut self,
18556        _: &StopLanguageServer,
18557        _: &mut Window,
18558        cx: &mut Context<Self>,
18559    ) {
18560        if let Some(project) = self.project.clone() {
18561            self.buffer.update(cx, |multi_buffer, cx| {
18562                project.update(cx, |project, cx| {
18563                    project.stop_language_servers_for_buffers(
18564                        multi_buffer.all_buffers().into_iter().collect(),
18565                        HashSet::default(),
18566                        cx,
18567                    );
18568                });
18569            });
18570            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18571        }
18572    }
18573
18574    fn cancel_language_server_work(
18575        workspace: &mut Workspace,
18576        _: &actions::CancelLanguageServerWork,
18577        _: &mut Window,
18578        cx: &mut Context<Workspace>,
18579    ) {
18580        let project = workspace.project();
18581        let buffers = workspace
18582            .active_item(cx)
18583            .and_then(|item| item.act_as::<Editor>(cx))
18584            .map_or(HashSet::default(), |editor| {
18585                editor.read(cx).buffer.read(cx).all_buffers()
18586            });
18587        project.update(cx, |project, cx| {
18588            project.cancel_language_server_work_for_buffers(buffers, cx);
18589        });
18590    }
18591
18592    fn show_character_palette(
18593        &mut self,
18594        _: &ShowCharacterPalette,
18595        window: &mut Window,
18596        _: &mut Context<Self>,
18597    ) {
18598        window.show_character_palette();
18599    }
18600
18601    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18602        if !self.diagnostics_enabled() {
18603            return;
18604        }
18605
18606        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18607            let buffer = self.buffer.read(cx).snapshot(cx);
18608            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18609            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18610            let is_valid = buffer
18611                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18612                .any(|entry| {
18613                    entry.diagnostic.is_primary
18614                        && !entry.range.is_empty()
18615                        && entry.range.start == primary_range_start
18616                        && entry.diagnostic.message == active_diagnostics.active_message
18617                });
18618
18619            if !is_valid {
18620                self.dismiss_diagnostics(cx);
18621            }
18622        }
18623    }
18624
18625    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18626        match &self.active_diagnostics {
18627            ActiveDiagnostic::Group(group) => Some(group),
18628            _ => None,
18629        }
18630    }
18631
18632    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18633        if !self.diagnostics_enabled() {
18634            return;
18635        }
18636        self.dismiss_diagnostics(cx);
18637        self.active_diagnostics = ActiveDiagnostic::All;
18638    }
18639
18640    fn activate_diagnostics(
18641        &mut self,
18642        buffer_id: BufferId,
18643        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18644        window: &mut Window,
18645        cx: &mut Context<Self>,
18646    ) {
18647        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18648            return;
18649        }
18650        self.dismiss_diagnostics(cx);
18651        let snapshot = self.snapshot(window, cx);
18652        let buffer = self.buffer.read(cx).snapshot(cx);
18653        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18654            return;
18655        };
18656
18657        let diagnostic_group = buffer
18658            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18659            .collect::<Vec<_>>();
18660
18661        let language_registry = self
18662            .project()
18663            .map(|project| project.read(cx).languages().clone());
18664
18665        let blocks = renderer.render_group(
18666            diagnostic_group,
18667            buffer_id,
18668            snapshot,
18669            cx.weak_entity(),
18670            language_registry,
18671            cx,
18672        );
18673
18674        let blocks = self.display_map.update(cx, |display_map, cx| {
18675            display_map.insert_blocks(blocks, cx).into_iter().collect()
18676        });
18677        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18678            active_range: buffer.anchor_before(diagnostic.range.start)
18679                ..buffer.anchor_after(diagnostic.range.end),
18680            active_message: diagnostic.diagnostic.message.clone(),
18681            group_id: diagnostic.diagnostic.group_id,
18682            blocks,
18683        });
18684        cx.notify();
18685    }
18686
18687    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18688        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18689            return;
18690        };
18691
18692        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18693        if let ActiveDiagnostic::Group(group) = prev {
18694            self.display_map.update(cx, |display_map, cx| {
18695                display_map.remove_blocks(group.blocks, cx);
18696            });
18697            cx.notify();
18698        }
18699    }
18700
18701    /// Disable inline diagnostics rendering for this editor.
18702    pub fn disable_inline_diagnostics(&mut self) {
18703        self.inline_diagnostics_enabled = false;
18704        self.inline_diagnostics_update = Task::ready(());
18705        self.inline_diagnostics.clear();
18706    }
18707
18708    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18709        self.diagnostics_enabled = false;
18710        self.dismiss_diagnostics(cx);
18711        self.inline_diagnostics_update = Task::ready(());
18712        self.inline_diagnostics.clear();
18713    }
18714
18715    pub fn disable_word_completions(&mut self) {
18716        self.word_completions_enabled = false;
18717    }
18718
18719    pub fn diagnostics_enabled(&self) -> bool {
18720        self.diagnostics_enabled && self.mode.is_full()
18721    }
18722
18723    pub fn inline_diagnostics_enabled(&self) -> bool {
18724        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18725    }
18726
18727    pub fn show_inline_diagnostics(&self) -> bool {
18728        self.show_inline_diagnostics
18729    }
18730
18731    pub fn toggle_inline_diagnostics(
18732        &mut self,
18733        _: &ToggleInlineDiagnostics,
18734        window: &mut Window,
18735        cx: &mut Context<Editor>,
18736    ) {
18737        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18738        self.refresh_inline_diagnostics(false, window, cx);
18739    }
18740
18741    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18742        self.diagnostics_max_severity = severity;
18743        self.display_map.update(cx, |display_map, _| {
18744            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18745        });
18746    }
18747
18748    pub fn toggle_diagnostics(
18749        &mut self,
18750        _: &ToggleDiagnostics,
18751        window: &mut Window,
18752        cx: &mut Context<Editor>,
18753    ) {
18754        if !self.diagnostics_enabled() {
18755            return;
18756        }
18757
18758        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18759            EditorSettings::get_global(cx)
18760                .diagnostics_max_severity
18761                .filter(|severity| severity != &DiagnosticSeverity::Off)
18762                .unwrap_or(DiagnosticSeverity::Hint)
18763        } else {
18764            DiagnosticSeverity::Off
18765        };
18766        self.set_max_diagnostics_severity(new_severity, cx);
18767        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18768            self.active_diagnostics = ActiveDiagnostic::None;
18769            self.inline_diagnostics_update = Task::ready(());
18770            self.inline_diagnostics.clear();
18771        } else {
18772            self.refresh_inline_diagnostics(false, window, cx);
18773        }
18774
18775        cx.notify();
18776    }
18777
18778    pub fn toggle_minimap(
18779        &mut self,
18780        _: &ToggleMinimap,
18781        window: &mut Window,
18782        cx: &mut Context<Editor>,
18783    ) {
18784        if self.supports_minimap(cx) {
18785            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18786        }
18787    }
18788
18789    fn refresh_inline_diagnostics(
18790        &mut self,
18791        debounce: bool,
18792        window: &mut Window,
18793        cx: &mut Context<Self>,
18794    ) {
18795        let max_severity = ProjectSettings::get_global(cx)
18796            .diagnostics
18797            .inline
18798            .max_severity
18799            .unwrap_or(self.diagnostics_max_severity);
18800
18801        if !self.inline_diagnostics_enabled()
18802            || !self.diagnostics_enabled()
18803            || !self.show_inline_diagnostics
18804            || max_severity == DiagnosticSeverity::Off
18805        {
18806            self.inline_diagnostics_update = Task::ready(());
18807            self.inline_diagnostics.clear();
18808            return;
18809        }
18810
18811        let debounce_ms = ProjectSettings::get_global(cx)
18812            .diagnostics
18813            .inline
18814            .update_debounce_ms;
18815        let debounce = if debounce && debounce_ms > 0 {
18816            Some(Duration::from_millis(debounce_ms))
18817        } else {
18818            None
18819        };
18820        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18821            if let Some(debounce) = debounce {
18822                cx.background_executor().timer(debounce).await;
18823            }
18824            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18825                editor
18826                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18827                    .ok()
18828            }) else {
18829                return;
18830            };
18831
18832            let new_inline_diagnostics = cx
18833                .background_spawn(async move {
18834                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18835                    for diagnostic_entry in
18836                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18837                    {
18838                        let message = diagnostic_entry
18839                            .diagnostic
18840                            .message
18841                            .split_once('\n')
18842                            .map(|(line, _)| line)
18843                            .map(SharedString::new)
18844                            .unwrap_or_else(|| {
18845                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18846                            });
18847                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18848                        let (Ok(i) | Err(i)) = inline_diagnostics
18849                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18850                        inline_diagnostics.insert(
18851                            i,
18852                            (
18853                                start_anchor,
18854                                InlineDiagnostic {
18855                                    message,
18856                                    group_id: diagnostic_entry.diagnostic.group_id,
18857                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18858                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18859                                    severity: diagnostic_entry.diagnostic.severity,
18860                                },
18861                            ),
18862                        );
18863                    }
18864                    inline_diagnostics
18865                })
18866                .await;
18867
18868            editor
18869                .update(cx, |editor, cx| {
18870                    editor.inline_diagnostics = new_inline_diagnostics;
18871                    cx.notify();
18872                })
18873                .ok();
18874        });
18875    }
18876
18877    fn pull_diagnostics(
18878        &mut self,
18879        buffer_id: Option<BufferId>,
18880        window: &Window,
18881        cx: &mut Context<Self>,
18882    ) -> Option<()> {
18883        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18884            return None;
18885        }
18886        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18887            .diagnostics
18888            .lsp_pull_diagnostics;
18889        if !pull_diagnostics_settings.enabled {
18890            return None;
18891        }
18892        let project = self.project()?.downgrade();
18893
18894        let mut edited_buffer_ids = HashSet::default();
18895        let mut edited_worktree_ids = HashSet::default();
18896        let edited_buffers = match buffer_id {
18897            Some(buffer_id) => {
18898                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
18899                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
18900                edited_buffer_ids.insert(buffer.read(cx).remote_id());
18901                edited_worktree_ids.insert(worktree_id);
18902                vec![buffer]
18903            }
18904            None => self
18905                .buffer()
18906                .read(cx)
18907                .all_buffers()
18908                .into_iter()
18909                .filter(|buffer| {
18910                    let buffer = buffer.read(cx);
18911                    match buffer.file().map(|f| f.worktree_id(cx)) {
18912                        Some(worktree_id) => {
18913                            edited_buffer_ids.insert(buffer.remote_id());
18914                            edited_worktree_ids.insert(worktree_id);
18915                            true
18916                        }
18917                        None => false,
18918                    }
18919                })
18920                .collect::<Vec<_>>(),
18921        };
18922
18923        if edited_buffers.is_empty() {
18924            self.pull_diagnostics_task = Task::ready(());
18925            self.pull_diagnostics_background_task = Task::ready(());
18926            return None;
18927        }
18928
18929        let mut already_used_buffers = HashSet::default();
18930        let related_open_buffers = self
18931            .workspace
18932            .as_ref()
18933            .and_then(|(workspace, _)| workspace.upgrade())
18934            .into_iter()
18935            .flat_map(|workspace| workspace.read(cx).panes())
18936            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
18937            .filter(|editor| editor != &cx.entity())
18938            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
18939            .filter(|buffer| {
18940                let buffer = buffer.read(cx);
18941                let buffer_id = buffer.remote_id();
18942                if already_used_buffers.insert(buffer_id) {
18943                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
18944                        return !edited_buffer_ids.contains(&buffer_id)
18945                            && !edited_worktree_ids.contains(&worktree_id);
18946                    }
18947                }
18948                false
18949            })
18950            .collect::<Vec<_>>();
18951
18952        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18953        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
18954            if buffers.is_empty() {
18955                return Task::ready(());
18956            }
18957            let project_weak = project.clone();
18958            cx.spawn_in(window, async move |_, cx| {
18959                cx.background_executor().timer(delay).await;
18960
18961                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18962                    buffers
18963                        .into_iter()
18964                        .filter_map(|buffer| {
18965                            project_weak
18966                                .update(cx, |project, cx| {
18967                                    project.lsp_store().update(cx, |lsp_store, cx| {
18968                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18969                                    })
18970                                })
18971                                .ok()
18972                        })
18973                        .collect::<FuturesUnordered<_>>()
18974                }) else {
18975                    return;
18976                };
18977
18978                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18979                    if let Err(e) = pull_task {
18980                        log::error!("Failed to update project diagnostics: {e:#}");
18981                    }
18982                }
18983            })
18984        };
18985
18986        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
18987        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
18988
18989        Some(())
18990    }
18991
18992    pub fn set_selections_from_remote(
18993        &mut self,
18994        selections: Vec<Selection<Anchor>>,
18995        pending_selection: Option<Selection<Anchor>>,
18996        window: &mut Window,
18997        cx: &mut Context<Self>,
18998    ) {
18999        let old_cursor_position = self.selections.newest_anchor().head();
19000        self.selections
19001            .change_with(&self.display_snapshot(cx), |s| {
19002                s.select_anchors(selections);
19003                if let Some(pending_selection) = pending_selection {
19004                    s.set_pending(pending_selection, SelectMode::Character);
19005                } else {
19006                    s.clear_pending();
19007                }
19008            });
19009        self.selections_did_change(
19010            false,
19011            &old_cursor_position,
19012            SelectionEffects::default(),
19013            window,
19014            cx,
19015        );
19016    }
19017
19018    pub fn transact(
19019        &mut self,
19020        window: &mut Window,
19021        cx: &mut Context<Self>,
19022        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
19023    ) -> Option<TransactionId> {
19024        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
19025            this.start_transaction_at(Instant::now(), window, cx);
19026            update(this, window, cx);
19027            this.end_transaction_at(Instant::now(), cx)
19028        })
19029    }
19030
19031    pub fn start_transaction_at(
19032        &mut self,
19033        now: Instant,
19034        window: &mut Window,
19035        cx: &mut Context<Self>,
19036    ) -> Option<TransactionId> {
19037        self.end_selection(window, cx);
19038        if let Some(tx_id) = self
19039            .buffer
19040            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
19041        {
19042            self.selection_history
19043                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
19044            cx.emit(EditorEvent::TransactionBegun {
19045                transaction_id: tx_id,
19046            });
19047            Some(tx_id)
19048        } else {
19049            None
19050        }
19051    }
19052
19053    pub fn end_transaction_at(
19054        &mut self,
19055        now: Instant,
19056        cx: &mut Context<Self>,
19057    ) -> Option<TransactionId> {
19058        if let Some(transaction_id) = self
19059            .buffer
19060            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
19061        {
19062            if let Some((_, end_selections)) =
19063                self.selection_history.transaction_mut(transaction_id)
19064            {
19065                *end_selections = Some(self.selections.disjoint_anchors_arc());
19066            } else {
19067                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
19068            }
19069
19070            cx.emit(EditorEvent::Edited { transaction_id });
19071            Some(transaction_id)
19072        } else {
19073            None
19074        }
19075    }
19076
19077    pub fn modify_transaction_selection_history(
19078        &mut self,
19079        transaction_id: TransactionId,
19080        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
19081    ) -> bool {
19082        self.selection_history
19083            .transaction_mut(transaction_id)
19084            .map(modify)
19085            .is_some()
19086    }
19087
19088    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
19089        if self.selection_mark_mode {
19090            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19091                s.move_with(|_, sel| {
19092                    sel.collapse_to(sel.head(), SelectionGoal::None);
19093                });
19094            })
19095        }
19096        self.selection_mark_mode = true;
19097        cx.notify();
19098    }
19099
19100    pub fn swap_selection_ends(
19101        &mut self,
19102        _: &actions::SwapSelectionEnds,
19103        window: &mut Window,
19104        cx: &mut Context<Self>,
19105    ) {
19106        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19107            s.move_with(|_, sel| {
19108                if sel.start != sel.end {
19109                    sel.reversed = !sel.reversed
19110                }
19111            });
19112        });
19113        self.request_autoscroll(Autoscroll::newest(), cx);
19114        cx.notify();
19115    }
19116
19117    pub fn toggle_focus(
19118        workspace: &mut Workspace,
19119        _: &actions::ToggleFocus,
19120        window: &mut Window,
19121        cx: &mut Context<Workspace>,
19122    ) {
19123        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19124            return;
19125        };
19126        workspace.activate_item(&item, true, true, window, cx);
19127    }
19128
19129    pub fn toggle_fold(
19130        &mut self,
19131        _: &actions::ToggleFold,
19132        window: &mut Window,
19133        cx: &mut Context<Self>,
19134    ) {
19135        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19136            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19137            let selection = self.selections.newest::<Point>(&display_map);
19138
19139            let range = if selection.is_empty() {
19140                let point = selection.head().to_display_point(&display_map);
19141                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19142                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19143                    .to_point(&display_map);
19144                start..end
19145            } else {
19146                selection.range()
19147            };
19148            if display_map.folds_in_range(range).next().is_some() {
19149                self.unfold_lines(&Default::default(), window, cx)
19150            } else {
19151                self.fold(&Default::default(), window, cx)
19152            }
19153        } else {
19154            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19155            let buffer_ids: HashSet<_> = self
19156                .selections
19157                .disjoint_anchor_ranges()
19158                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19159                .collect();
19160
19161            let should_unfold = buffer_ids
19162                .iter()
19163                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19164
19165            for buffer_id in buffer_ids {
19166                if should_unfold {
19167                    self.unfold_buffer(buffer_id, cx);
19168                } else {
19169                    self.fold_buffer(buffer_id, cx);
19170                }
19171            }
19172        }
19173    }
19174
19175    pub fn toggle_fold_recursive(
19176        &mut self,
19177        _: &actions::ToggleFoldRecursive,
19178        window: &mut Window,
19179        cx: &mut Context<Self>,
19180    ) {
19181        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19182
19183        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19184        let range = if selection.is_empty() {
19185            let point = selection.head().to_display_point(&display_map);
19186            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19187            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19188                .to_point(&display_map);
19189            start..end
19190        } else {
19191            selection.range()
19192        };
19193        if display_map.folds_in_range(range).next().is_some() {
19194            self.unfold_recursive(&Default::default(), window, cx)
19195        } else {
19196            self.fold_recursive(&Default::default(), window, cx)
19197        }
19198    }
19199
19200    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19201        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19202            let mut to_fold = Vec::new();
19203            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19204            let selections = self.selections.all_adjusted(&display_map);
19205
19206            for selection in selections {
19207                let range = selection.range().sorted();
19208                let buffer_start_row = range.start.row;
19209
19210                if range.start.row != range.end.row {
19211                    let mut found = false;
19212                    let mut row = range.start.row;
19213                    while row <= range.end.row {
19214                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19215                        {
19216                            found = true;
19217                            row = crease.range().end.row + 1;
19218                            to_fold.push(crease);
19219                        } else {
19220                            row += 1
19221                        }
19222                    }
19223                    if found {
19224                        continue;
19225                    }
19226                }
19227
19228                for row in (0..=range.start.row).rev() {
19229                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19230                        && crease.range().end.row >= buffer_start_row
19231                    {
19232                        to_fold.push(crease);
19233                        if row <= range.start.row {
19234                            break;
19235                        }
19236                    }
19237                }
19238            }
19239
19240            self.fold_creases(to_fold, true, window, cx);
19241        } else {
19242            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19243            let buffer_ids = self
19244                .selections
19245                .disjoint_anchor_ranges()
19246                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19247                .collect::<HashSet<_>>();
19248            for buffer_id in buffer_ids {
19249                self.fold_buffer(buffer_id, cx);
19250            }
19251        }
19252    }
19253
19254    pub fn toggle_fold_all(
19255        &mut self,
19256        _: &actions::ToggleFoldAll,
19257        window: &mut Window,
19258        cx: &mut Context<Self>,
19259    ) {
19260        if self.buffer.read(cx).is_singleton() {
19261            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19262            let has_folds = display_map
19263                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19264                .next()
19265                .is_some();
19266
19267            if has_folds {
19268                self.unfold_all(&actions::UnfoldAll, window, cx);
19269            } else {
19270                self.fold_all(&actions::FoldAll, window, cx);
19271            }
19272        } else {
19273            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19274            let should_unfold = buffer_ids
19275                .iter()
19276                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19277
19278            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19279                editor
19280                    .update_in(cx, |editor, _, cx| {
19281                        for buffer_id in buffer_ids {
19282                            if should_unfold {
19283                                editor.unfold_buffer(buffer_id, cx);
19284                            } else {
19285                                editor.fold_buffer(buffer_id, cx);
19286                            }
19287                        }
19288                    })
19289                    .ok();
19290            });
19291        }
19292    }
19293
19294    fn fold_at_level(
19295        &mut self,
19296        fold_at: &FoldAtLevel,
19297        window: &mut Window,
19298        cx: &mut Context<Self>,
19299    ) {
19300        if !self.buffer.read(cx).is_singleton() {
19301            return;
19302        }
19303
19304        let fold_at_level = fold_at.0;
19305        let snapshot = self.buffer.read(cx).snapshot(cx);
19306        let mut to_fold = Vec::new();
19307        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19308
19309        let row_ranges_to_keep: Vec<Range<u32>> = self
19310            .selections
19311            .all::<Point>(&self.display_snapshot(cx))
19312            .into_iter()
19313            .map(|sel| sel.start.row..sel.end.row)
19314            .collect();
19315
19316        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19317            while start_row < end_row {
19318                match self
19319                    .snapshot(window, cx)
19320                    .crease_for_buffer_row(MultiBufferRow(start_row))
19321                {
19322                    Some(crease) => {
19323                        let nested_start_row = crease.range().start.row + 1;
19324                        let nested_end_row = crease.range().end.row;
19325
19326                        if current_level < fold_at_level {
19327                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19328                        } else if current_level == fold_at_level {
19329                            // Fold iff there is no selection completely contained within the fold region
19330                            if !row_ranges_to_keep.iter().any(|selection| {
19331                                selection.end >= nested_start_row
19332                                    && selection.start <= nested_end_row
19333                            }) {
19334                                to_fold.push(crease);
19335                            }
19336                        }
19337
19338                        start_row = nested_end_row + 1;
19339                    }
19340                    None => start_row += 1,
19341                }
19342            }
19343        }
19344
19345        self.fold_creases(to_fold, true, window, cx);
19346    }
19347
19348    pub fn fold_at_level_1(
19349        &mut self,
19350        _: &actions::FoldAtLevel1,
19351        window: &mut Window,
19352        cx: &mut Context<Self>,
19353    ) {
19354        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19355    }
19356
19357    pub fn fold_at_level_2(
19358        &mut self,
19359        _: &actions::FoldAtLevel2,
19360        window: &mut Window,
19361        cx: &mut Context<Self>,
19362    ) {
19363        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19364    }
19365
19366    pub fn fold_at_level_3(
19367        &mut self,
19368        _: &actions::FoldAtLevel3,
19369        window: &mut Window,
19370        cx: &mut Context<Self>,
19371    ) {
19372        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19373    }
19374
19375    pub fn fold_at_level_4(
19376        &mut self,
19377        _: &actions::FoldAtLevel4,
19378        window: &mut Window,
19379        cx: &mut Context<Self>,
19380    ) {
19381        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19382    }
19383
19384    pub fn fold_at_level_5(
19385        &mut self,
19386        _: &actions::FoldAtLevel5,
19387        window: &mut Window,
19388        cx: &mut Context<Self>,
19389    ) {
19390        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19391    }
19392
19393    pub fn fold_at_level_6(
19394        &mut self,
19395        _: &actions::FoldAtLevel6,
19396        window: &mut Window,
19397        cx: &mut Context<Self>,
19398    ) {
19399        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19400    }
19401
19402    pub fn fold_at_level_7(
19403        &mut self,
19404        _: &actions::FoldAtLevel7,
19405        window: &mut Window,
19406        cx: &mut Context<Self>,
19407    ) {
19408        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19409    }
19410
19411    pub fn fold_at_level_8(
19412        &mut self,
19413        _: &actions::FoldAtLevel8,
19414        window: &mut Window,
19415        cx: &mut Context<Self>,
19416    ) {
19417        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19418    }
19419
19420    pub fn fold_at_level_9(
19421        &mut self,
19422        _: &actions::FoldAtLevel9,
19423        window: &mut Window,
19424        cx: &mut Context<Self>,
19425    ) {
19426        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19427    }
19428
19429    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19430        if self.buffer.read(cx).is_singleton() {
19431            let mut fold_ranges = Vec::new();
19432            let snapshot = self.buffer.read(cx).snapshot(cx);
19433
19434            for row in 0..snapshot.max_row().0 {
19435                if let Some(foldable_range) = self
19436                    .snapshot(window, cx)
19437                    .crease_for_buffer_row(MultiBufferRow(row))
19438                {
19439                    fold_ranges.push(foldable_range);
19440                }
19441            }
19442
19443            self.fold_creases(fold_ranges, true, window, cx);
19444        } else {
19445            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19446                editor
19447                    .update_in(cx, |editor, _, cx| {
19448                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19449                            editor.fold_buffer(buffer_id, cx);
19450                        }
19451                    })
19452                    .ok();
19453            });
19454        }
19455    }
19456
19457    pub fn fold_function_bodies(
19458        &mut self,
19459        _: &actions::FoldFunctionBodies,
19460        window: &mut Window,
19461        cx: &mut Context<Self>,
19462    ) {
19463        let snapshot = self.buffer.read(cx).snapshot(cx);
19464
19465        let ranges = snapshot
19466            .text_object_ranges(
19467                MultiBufferOffset(0)..snapshot.len(),
19468                TreeSitterOptions::default(),
19469            )
19470            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19471            .collect::<Vec<_>>();
19472
19473        let creases = ranges
19474            .into_iter()
19475            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19476            .collect();
19477
19478        self.fold_creases(creases, true, window, cx);
19479    }
19480
19481    pub fn fold_recursive(
19482        &mut self,
19483        _: &actions::FoldRecursive,
19484        window: &mut Window,
19485        cx: &mut Context<Self>,
19486    ) {
19487        let mut to_fold = Vec::new();
19488        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19489        let selections = self.selections.all_adjusted(&display_map);
19490
19491        for selection in selections {
19492            let range = selection.range().sorted();
19493            let buffer_start_row = range.start.row;
19494
19495            if range.start.row != range.end.row {
19496                let mut found = false;
19497                for row in range.start.row..=range.end.row {
19498                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19499                        found = true;
19500                        to_fold.push(crease);
19501                    }
19502                }
19503                if found {
19504                    continue;
19505                }
19506            }
19507
19508            for row in (0..=range.start.row).rev() {
19509                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19510                    if crease.range().end.row >= buffer_start_row {
19511                        to_fold.push(crease);
19512                    } else {
19513                        break;
19514                    }
19515                }
19516            }
19517        }
19518
19519        self.fold_creases(to_fold, true, window, cx);
19520    }
19521
19522    pub fn fold_at(
19523        &mut self,
19524        buffer_row: MultiBufferRow,
19525        window: &mut Window,
19526        cx: &mut Context<Self>,
19527    ) {
19528        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19529
19530        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19531            let autoscroll = self
19532                .selections
19533                .all::<Point>(&display_map)
19534                .iter()
19535                .any(|selection| crease.range().overlaps(&selection.range()));
19536
19537            self.fold_creases(vec![crease], autoscroll, window, cx);
19538        }
19539    }
19540
19541    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19542        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19543            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19544            let buffer = display_map.buffer_snapshot();
19545            let selections = self.selections.all::<Point>(&display_map);
19546            let ranges = selections
19547                .iter()
19548                .map(|s| {
19549                    let range = s.display_range(&display_map).sorted();
19550                    let mut start = range.start.to_point(&display_map);
19551                    let mut end = range.end.to_point(&display_map);
19552                    start.column = 0;
19553                    end.column = buffer.line_len(MultiBufferRow(end.row));
19554                    start..end
19555                })
19556                .collect::<Vec<_>>();
19557
19558            self.unfold_ranges(&ranges, true, true, cx);
19559        } else {
19560            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19561            let buffer_ids = self
19562                .selections
19563                .disjoint_anchor_ranges()
19564                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19565                .collect::<HashSet<_>>();
19566            for buffer_id in buffer_ids {
19567                self.unfold_buffer(buffer_id, cx);
19568            }
19569        }
19570    }
19571
19572    pub fn unfold_recursive(
19573        &mut self,
19574        _: &UnfoldRecursive,
19575        _window: &mut Window,
19576        cx: &mut Context<Self>,
19577    ) {
19578        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19579        let selections = self.selections.all::<Point>(&display_map);
19580        let ranges = selections
19581            .iter()
19582            .map(|s| {
19583                let mut range = s.display_range(&display_map).sorted();
19584                *range.start.column_mut() = 0;
19585                *range.end.column_mut() = display_map.line_len(range.end.row());
19586                let start = range.start.to_point(&display_map);
19587                let end = range.end.to_point(&display_map);
19588                start..end
19589            })
19590            .collect::<Vec<_>>();
19591
19592        self.unfold_ranges(&ranges, true, true, cx);
19593    }
19594
19595    pub fn unfold_at(
19596        &mut self,
19597        buffer_row: MultiBufferRow,
19598        _window: &mut Window,
19599        cx: &mut Context<Self>,
19600    ) {
19601        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19602
19603        let intersection_range = Point::new(buffer_row.0, 0)
19604            ..Point::new(
19605                buffer_row.0,
19606                display_map.buffer_snapshot().line_len(buffer_row),
19607            );
19608
19609        let autoscroll = self
19610            .selections
19611            .all::<Point>(&display_map)
19612            .iter()
19613            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19614
19615        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19616    }
19617
19618    pub fn unfold_all(
19619        &mut self,
19620        _: &actions::UnfoldAll,
19621        _window: &mut Window,
19622        cx: &mut Context<Self>,
19623    ) {
19624        if self.buffer.read(cx).is_singleton() {
19625            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19626            self.unfold_ranges(
19627                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19628                true,
19629                true,
19630                cx,
19631            );
19632        } else {
19633            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19634                editor
19635                    .update(cx, |editor, cx| {
19636                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19637                            editor.unfold_buffer(buffer_id, cx);
19638                        }
19639                    })
19640                    .ok();
19641            });
19642        }
19643    }
19644
19645    pub fn fold_selected_ranges(
19646        &mut self,
19647        _: &FoldSelectedRanges,
19648        window: &mut Window,
19649        cx: &mut Context<Self>,
19650    ) {
19651        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19652        let selections = self.selections.all_adjusted(&display_map);
19653        let ranges = selections
19654            .into_iter()
19655            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19656            .collect::<Vec<_>>();
19657        self.fold_creases(ranges, true, window, cx);
19658    }
19659
19660    pub fn fold_ranges<T: ToOffset + Clone>(
19661        &mut self,
19662        ranges: Vec<Range<T>>,
19663        auto_scroll: bool,
19664        window: &mut Window,
19665        cx: &mut Context<Self>,
19666    ) {
19667        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19668        let ranges = ranges
19669            .into_iter()
19670            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19671            .collect::<Vec<_>>();
19672        self.fold_creases(ranges, auto_scroll, window, cx);
19673    }
19674
19675    pub fn fold_creases<T: ToOffset + Clone>(
19676        &mut self,
19677        creases: Vec<Crease<T>>,
19678        auto_scroll: bool,
19679        _window: &mut Window,
19680        cx: &mut Context<Self>,
19681    ) {
19682        if creases.is_empty() {
19683            return;
19684        }
19685
19686        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19687
19688        if auto_scroll {
19689            self.request_autoscroll(Autoscroll::fit(), cx);
19690        }
19691
19692        cx.notify();
19693
19694        self.scrollbar_marker_state.dirty = true;
19695        self.folds_did_change(cx);
19696    }
19697
19698    /// Removes any folds whose ranges intersect any of the given ranges.
19699    pub fn unfold_ranges<T: ToOffset + Clone>(
19700        &mut self,
19701        ranges: &[Range<T>],
19702        inclusive: bool,
19703        auto_scroll: bool,
19704        cx: &mut Context<Self>,
19705    ) {
19706        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19707            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19708        });
19709        self.folds_did_change(cx);
19710    }
19711
19712    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19713        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19714            return;
19715        }
19716
19717        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19718        self.display_map.update(cx, |display_map, cx| {
19719            display_map.fold_buffers([buffer_id], cx)
19720        });
19721
19722        let snapshot = self.display_snapshot(cx);
19723        self.selections.change_with(&snapshot, |selections| {
19724            selections.remove_selections_from_buffer(buffer_id);
19725        });
19726
19727        cx.emit(EditorEvent::BufferFoldToggled {
19728            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19729            folded: true,
19730        });
19731        cx.notify();
19732    }
19733
19734    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19735        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19736            return;
19737        }
19738        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19739        self.display_map.update(cx, |display_map, cx| {
19740            display_map.unfold_buffers([buffer_id], cx);
19741        });
19742        cx.emit(EditorEvent::BufferFoldToggled {
19743            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19744            folded: false,
19745        });
19746        cx.notify();
19747    }
19748
19749    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19750        self.display_map.read(cx).is_buffer_folded(buffer)
19751    }
19752
19753    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19754        self.display_map.read(cx).folded_buffers()
19755    }
19756
19757    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19758        self.display_map.update(cx, |display_map, cx| {
19759            display_map.disable_header_for_buffer(buffer_id, cx);
19760        });
19761        cx.notify();
19762    }
19763
19764    /// Removes any folds with the given ranges.
19765    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19766        &mut self,
19767        ranges: &[Range<T>],
19768        type_id: TypeId,
19769        auto_scroll: bool,
19770        cx: &mut Context<Self>,
19771    ) {
19772        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19773            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19774        });
19775        self.folds_did_change(cx);
19776    }
19777
19778    fn remove_folds_with<T: ToOffset + Clone>(
19779        &mut self,
19780        ranges: &[Range<T>],
19781        auto_scroll: bool,
19782        cx: &mut Context<Self>,
19783        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19784    ) {
19785        if ranges.is_empty() {
19786            return;
19787        }
19788
19789        let mut buffers_affected = HashSet::default();
19790        let multi_buffer = self.buffer().read(cx);
19791        for range in ranges {
19792            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19793                buffers_affected.insert(buffer.read(cx).remote_id());
19794            };
19795        }
19796
19797        self.display_map.update(cx, update);
19798
19799        if auto_scroll {
19800            self.request_autoscroll(Autoscroll::fit(), cx);
19801        }
19802
19803        cx.notify();
19804        self.scrollbar_marker_state.dirty = true;
19805        self.active_indent_guides_state.dirty = true;
19806    }
19807
19808    pub fn update_renderer_widths(
19809        &mut self,
19810        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19811        cx: &mut Context<Self>,
19812    ) -> bool {
19813        self.display_map
19814            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19815    }
19816
19817    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19818        self.display_map.read(cx).fold_placeholder.clone()
19819    }
19820
19821    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19822        self.buffer.update(cx, |buffer, cx| {
19823            buffer.set_all_diff_hunks_expanded(cx);
19824        });
19825    }
19826
19827    pub fn expand_all_diff_hunks(
19828        &mut self,
19829        _: &ExpandAllDiffHunks,
19830        _window: &mut Window,
19831        cx: &mut Context<Self>,
19832    ) {
19833        self.buffer.update(cx, |buffer, cx| {
19834            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19835        });
19836    }
19837
19838    pub fn collapse_all_diff_hunks(
19839        &mut self,
19840        _: &CollapseAllDiffHunks,
19841        _window: &mut Window,
19842        cx: &mut Context<Self>,
19843    ) {
19844        self.buffer.update(cx, |buffer, cx| {
19845            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19846        });
19847    }
19848
19849    pub fn toggle_selected_diff_hunks(
19850        &mut self,
19851        _: &ToggleSelectedDiffHunks,
19852        _window: &mut Window,
19853        cx: &mut Context<Self>,
19854    ) {
19855        let ranges: Vec<_> = self
19856            .selections
19857            .disjoint_anchors()
19858            .iter()
19859            .map(|s| s.range())
19860            .collect();
19861        self.toggle_diff_hunks_in_ranges(ranges, cx);
19862    }
19863
19864    pub fn diff_hunks_in_ranges<'a>(
19865        &'a self,
19866        ranges: &'a [Range<Anchor>],
19867        buffer: &'a MultiBufferSnapshot,
19868    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19869        ranges.iter().flat_map(move |range| {
19870            let end_excerpt_id = range.end.excerpt_id;
19871            let range = range.to_point(buffer);
19872            let mut peek_end = range.end;
19873            if range.end.row < buffer.max_row().0 {
19874                peek_end = Point::new(range.end.row + 1, 0);
19875            }
19876            buffer
19877                .diff_hunks_in_range(range.start..peek_end)
19878                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19879        })
19880    }
19881
19882    pub fn has_stageable_diff_hunks_in_ranges(
19883        &self,
19884        ranges: &[Range<Anchor>],
19885        snapshot: &MultiBufferSnapshot,
19886    ) -> bool {
19887        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19888        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19889    }
19890
19891    pub fn toggle_staged_selected_diff_hunks(
19892        &mut self,
19893        _: &::git::ToggleStaged,
19894        _: &mut Window,
19895        cx: &mut Context<Self>,
19896    ) {
19897        let snapshot = self.buffer.read(cx).snapshot(cx);
19898        let ranges: Vec<_> = self
19899            .selections
19900            .disjoint_anchors()
19901            .iter()
19902            .map(|s| s.range())
19903            .collect();
19904        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19905        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19906    }
19907
19908    pub fn set_render_diff_hunk_controls(
19909        &mut self,
19910        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19911        cx: &mut Context<Self>,
19912    ) {
19913        self.render_diff_hunk_controls = render_diff_hunk_controls;
19914        cx.notify();
19915    }
19916
19917    pub fn stage_and_next(
19918        &mut self,
19919        _: &::git::StageAndNext,
19920        window: &mut Window,
19921        cx: &mut Context<Self>,
19922    ) {
19923        self.do_stage_or_unstage_and_next(true, window, cx);
19924    }
19925
19926    pub fn unstage_and_next(
19927        &mut self,
19928        _: &::git::UnstageAndNext,
19929        window: &mut Window,
19930        cx: &mut Context<Self>,
19931    ) {
19932        self.do_stage_or_unstage_and_next(false, window, cx);
19933    }
19934
19935    pub fn stage_or_unstage_diff_hunks(
19936        &mut self,
19937        stage: bool,
19938        ranges: Vec<Range<Anchor>>,
19939        cx: &mut Context<Self>,
19940    ) {
19941        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19942        cx.spawn(async move |this, cx| {
19943            task.await?;
19944            this.update(cx, |this, cx| {
19945                let snapshot = this.buffer.read(cx).snapshot(cx);
19946                let chunk_by = this
19947                    .diff_hunks_in_ranges(&ranges, &snapshot)
19948                    .chunk_by(|hunk| hunk.buffer_id);
19949                for (buffer_id, hunks) in &chunk_by {
19950                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19951                }
19952            })
19953        })
19954        .detach_and_log_err(cx);
19955    }
19956
19957    fn save_buffers_for_ranges_if_needed(
19958        &mut self,
19959        ranges: &[Range<Anchor>],
19960        cx: &mut Context<Editor>,
19961    ) -> Task<Result<()>> {
19962        let multibuffer = self.buffer.read(cx);
19963        let snapshot = multibuffer.read(cx);
19964        let buffer_ids: HashSet<_> = ranges
19965            .iter()
19966            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19967            .collect();
19968        drop(snapshot);
19969
19970        let mut buffers = HashSet::default();
19971        for buffer_id in buffer_ids {
19972            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19973                let buffer = buffer_entity.read(cx);
19974                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19975                {
19976                    buffers.insert(buffer_entity);
19977                }
19978            }
19979        }
19980
19981        if let Some(project) = &self.project {
19982            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19983        } else {
19984            Task::ready(Ok(()))
19985        }
19986    }
19987
19988    fn do_stage_or_unstage_and_next(
19989        &mut self,
19990        stage: bool,
19991        window: &mut Window,
19992        cx: &mut Context<Self>,
19993    ) {
19994        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19995
19996        if ranges.iter().any(|range| range.start != range.end) {
19997            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19998            return;
19999        }
20000
20001        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20002        let snapshot = self.snapshot(window, cx);
20003        let position = self
20004            .selections
20005            .newest::<Point>(&snapshot.display_snapshot)
20006            .head();
20007        let mut row = snapshot
20008            .buffer_snapshot()
20009            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
20010            .find(|hunk| hunk.row_range.start.0 > position.row)
20011            .map(|hunk| hunk.row_range.start);
20012
20013        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
20014        // Outside of the project diff editor, wrap around to the beginning.
20015        if !all_diff_hunks_expanded {
20016            row = row.or_else(|| {
20017                snapshot
20018                    .buffer_snapshot()
20019                    .diff_hunks_in_range(Point::zero()..position)
20020                    .find(|hunk| hunk.row_range.end.0 < position.row)
20021                    .map(|hunk| hunk.row_range.start)
20022            });
20023        }
20024
20025        if let Some(row) = row {
20026            let destination = Point::new(row.0, 0);
20027            let autoscroll = Autoscroll::center();
20028
20029            self.unfold_ranges(&[destination..destination], false, false, cx);
20030            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
20031                s.select_ranges([destination..destination]);
20032            });
20033        }
20034    }
20035
20036    fn do_stage_or_unstage(
20037        &self,
20038        stage: bool,
20039        buffer_id: BufferId,
20040        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
20041        cx: &mut App,
20042    ) -> Option<()> {
20043        let project = self.project()?;
20044        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
20045        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
20046        let buffer_snapshot = buffer.read(cx).snapshot();
20047        let file_exists = buffer_snapshot
20048            .file()
20049            .is_some_and(|file| file.disk_state().exists());
20050        diff.update(cx, |diff, cx| {
20051            diff.stage_or_unstage_hunks(
20052                stage,
20053                &hunks
20054                    .map(|hunk| buffer_diff::DiffHunk {
20055                        buffer_range: hunk.buffer_range,
20056                        // We don't need to pass in word diffs here because they're only used for rendering and
20057                        // this function changes internal state
20058                        base_word_diffs: Vec::default(),
20059                        buffer_word_diffs: Vec::default(),
20060                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
20061                            ..hunk.diff_base_byte_range.end.0,
20062                        secondary_status: hunk.status.secondary,
20063                        range: Point::zero()..Point::zero(), // unused
20064                    })
20065                    .collect::<Vec<_>>(),
20066                &buffer_snapshot,
20067                file_exists,
20068                cx,
20069            )
20070        });
20071        None
20072    }
20073
20074    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
20075        let ranges: Vec<_> = self
20076            .selections
20077            .disjoint_anchors()
20078            .iter()
20079            .map(|s| s.range())
20080            .collect();
20081        self.buffer
20082            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
20083    }
20084
20085    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
20086        self.buffer.update(cx, |buffer, cx| {
20087            let ranges = vec![Anchor::min()..Anchor::max()];
20088            if !buffer.all_diff_hunks_expanded()
20089                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
20090            {
20091                buffer.collapse_diff_hunks(ranges, cx);
20092                true
20093            } else {
20094                false
20095            }
20096        })
20097    }
20098
20099    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
20100        if self.buffer.read(cx).all_diff_hunks_expanded() {
20101            return true;
20102        }
20103        let ranges = vec![Anchor::min()..Anchor::max()];
20104        self.buffer
20105            .read(cx)
20106            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
20107    }
20108
20109    fn toggle_diff_hunks_in_ranges(
20110        &mut self,
20111        ranges: Vec<Range<Anchor>>,
20112        cx: &mut Context<Editor>,
20113    ) {
20114        self.buffer.update(cx, |buffer, cx| {
20115            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
20116            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
20117        })
20118    }
20119
20120    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20121        self.buffer.update(cx, |buffer, cx| {
20122            let snapshot = buffer.snapshot(cx);
20123            let excerpt_id = range.end.excerpt_id;
20124            let point_range = range.to_point(&snapshot);
20125            let expand = !buffer.single_hunk_is_expanded(range, cx);
20126            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
20127        })
20128    }
20129
20130    pub(crate) fn apply_all_diff_hunks(
20131        &mut self,
20132        _: &ApplyAllDiffHunks,
20133        window: &mut Window,
20134        cx: &mut Context<Self>,
20135    ) {
20136        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20137
20138        let buffers = self.buffer.read(cx).all_buffers();
20139        for branch_buffer in buffers {
20140            branch_buffer.update(cx, |branch_buffer, cx| {
20141                branch_buffer.merge_into_base(Vec::new(), cx);
20142            });
20143        }
20144
20145        if let Some(project) = self.project.clone() {
20146            self.save(
20147                SaveOptions {
20148                    format: true,
20149                    autosave: false,
20150                },
20151                project,
20152                window,
20153                cx,
20154            )
20155            .detach_and_log_err(cx);
20156        }
20157    }
20158
20159    pub(crate) fn apply_selected_diff_hunks(
20160        &mut self,
20161        _: &ApplyDiffHunk,
20162        window: &mut Window,
20163        cx: &mut Context<Self>,
20164    ) {
20165        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20166        let snapshot = self.snapshot(window, cx);
20167        let hunks = snapshot.hunks_for_ranges(
20168            self.selections
20169                .all(&snapshot.display_snapshot)
20170                .into_iter()
20171                .map(|selection| selection.range()),
20172        );
20173        let mut ranges_by_buffer = HashMap::default();
20174        self.transact(window, cx, |editor, _window, cx| {
20175            for hunk in hunks {
20176                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20177                    ranges_by_buffer
20178                        .entry(buffer.clone())
20179                        .or_insert_with(Vec::new)
20180                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20181                }
20182            }
20183
20184            for (buffer, ranges) in ranges_by_buffer {
20185                buffer.update(cx, |buffer, cx| {
20186                    buffer.merge_into_base(ranges, cx);
20187                });
20188            }
20189        });
20190
20191        if let Some(project) = self.project.clone() {
20192            self.save(
20193                SaveOptions {
20194                    format: true,
20195                    autosave: false,
20196                },
20197                project,
20198                window,
20199                cx,
20200            )
20201            .detach_and_log_err(cx);
20202        }
20203    }
20204
20205    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20206        if hovered != self.gutter_hovered {
20207            self.gutter_hovered = hovered;
20208            cx.notify();
20209        }
20210    }
20211
20212    pub fn insert_blocks(
20213        &mut self,
20214        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20215        autoscroll: Option<Autoscroll>,
20216        cx: &mut Context<Self>,
20217    ) -> Vec<CustomBlockId> {
20218        let blocks = self
20219            .display_map
20220            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20221        if let Some(autoscroll) = autoscroll {
20222            self.request_autoscroll(autoscroll, cx);
20223        }
20224        cx.notify();
20225        blocks
20226    }
20227
20228    pub fn resize_blocks(
20229        &mut self,
20230        heights: HashMap<CustomBlockId, u32>,
20231        autoscroll: Option<Autoscroll>,
20232        cx: &mut Context<Self>,
20233    ) {
20234        self.display_map
20235            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20236        if let Some(autoscroll) = autoscroll {
20237            self.request_autoscroll(autoscroll, cx);
20238        }
20239        cx.notify();
20240    }
20241
20242    pub fn replace_blocks(
20243        &mut self,
20244        renderers: HashMap<CustomBlockId, RenderBlock>,
20245        autoscroll: Option<Autoscroll>,
20246        cx: &mut Context<Self>,
20247    ) {
20248        self.display_map
20249            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20250        if let Some(autoscroll) = autoscroll {
20251            self.request_autoscroll(autoscroll, cx);
20252        }
20253        cx.notify();
20254    }
20255
20256    pub fn remove_blocks(
20257        &mut self,
20258        block_ids: HashSet<CustomBlockId>,
20259        autoscroll: Option<Autoscroll>,
20260        cx: &mut Context<Self>,
20261    ) {
20262        self.display_map.update(cx, |display_map, cx| {
20263            display_map.remove_blocks(block_ids, cx)
20264        });
20265        if let Some(autoscroll) = autoscroll {
20266            self.request_autoscroll(autoscroll, cx);
20267        }
20268        cx.notify();
20269    }
20270
20271    pub fn row_for_block(
20272        &self,
20273        block_id: CustomBlockId,
20274        cx: &mut Context<Self>,
20275    ) -> Option<DisplayRow> {
20276        self.display_map
20277            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20278    }
20279
20280    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20281        self.focused_block = Some(focused_block);
20282    }
20283
20284    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20285        self.focused_block.take()
20286    }
20287
20288    pub fn insert_creases(
20289        &mut self,
20290        creases: impl IntoIterator<Item = Crease<Anchor>>,
20291        cx: &mut Context<Self>,
20292    ) -> Vec<CreaseId> {
20293        self.display_map
20294            .update(cx, |map, cx| map.insert_creases(creases, cx))
20295    }
20296
20297    pub fn remove_creases(
20298        &mut self,
20299        ids: impl IntoIterator<Item = CreaseId>,
20300        cx: &mut Context<Self>,
20301    ) -> Vec<(CreaseId, Range<Anchor>)> {
20302        self.display_map
20303            .update(cx, |map, cx| map.remove_creases(ids, cx))
20304    }
20305
20306    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20307        self.display_map
20308            .update(cx, |map, cx| map.snapshot(cx))
20309            .longest_row()
20310    }
20311
20312    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20313        self.display_map
20314            .update(cx, |map, cx| map.snapshot(cx))
20315            .max_point()
20316    }
20317
20318    pub fn text(&self, cx: &App) -> String {
20319        self.buffer.read(cx).read(cx).text()
20320    }
20321
20322    pub fn is_empty(&self, cx: &App) -> bool {
20323        self.buffer.read(cx).read(cx).is_empty()
20324    }
20325
20326    pub fn text_option(&self, cx: &App) -> Option<String> {
20327        let text = self.text(cx);
20328        let text = text.trim();
20329
20330        if text.is_empty() {
20331            return None;
20332        }
20333
20334        Some(text.to_string())
20335    }
20336
20337    pub fn set_text(
20338        &mut self,
20339        text: impl Into<Arc<str>>,
20340        window: &mut Window,
20341        cx: &mut Context<Self>,
20342    ) {
20343        self.transact(window, cx, |this, _, cx| {
20344            this.buffer
20345                .read(cx)
20346                .as_singleton()
20347                .expect("you can only call set_text on editors for singleton buffers")
20348                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20349        });
20350    }
20351
20352    pub fn display_text(&self, cx: &mut App) -> String {
20353        self.display_map
20354            .update(cx, |map, cx| map.snapshot(cx))
20355            .text()
20356    }
20357
20358    fn create_minimap(
20359        &self,
20360        minimap_settings: MinimapSettings,
20361        window: &mut Window,
20362        cx: &mut Context<Self>,
20363    ) -> Option<Entity<Self>> {
20364        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20365            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20366    }
20367
20368    fn initialize_new_minimap(
20369        &self,
20370        minimap_settings: MinimapSettings,
20371        window: &mut Window,
20372        cx: &mut Context<Self>,
20373    ) -> Entity<Self> {
20374        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20375        const MINIMAP_FONT_FAMILY: SharedString = SharedString::new_static(".ZedMono");
20376
20377        let mut minimap = Editor::new_internal(
20378            EditorMode::Minimap {
20379                parent: cx.weak_entity(),
20380            },
20381            self.buffer.clone(),
20382            None,
20383            Some(self.display_map.clone()),
20384            window,
20385            cx,
20386        );
20387        minimap.scroll_manager.clone_state(&self.scroll_manager);
20388        minimap.set_text_style_refinement(TextStyleRefinement {
20389            font_size: Some(MINIMAP_FONT_SIZE),
20390            font_weight: Some(MINIMAP_FONT_WEIGHT),
20391            font_family: Some(MINIMAP_FONT_FAMILY),
20392            ..Default::default()
20393        });
20394        minimap.update_minimap_configuration(minimap_settings, cx);
20395        cx.new(|_| minimap)
20396    }
20397
20398    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20399        let current_line_highlight = minimap_settings
20400            .current_line_highlight
20401            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20402        self.set_current_line_highlight(Some(current_line_highlight));
20403    }
20404
20405    pub fn minimap(&self) -> Option<&Entity<Self>> {
20406        self.minimap
20407            .as_ref()
20408            .filter(|_| self.minimap_visibility.visible())
20409    }
20410
20411    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20412        let mut wrap_guides = smallvec![];
20413
20414        if self.show_wrap_guides == Some(false) {
20415            return wrap_guides;
20416        }
20417
20418        let settings = self.buffer.read(cx).language_settings(cx);
20419        if settings.show_wrap_guides {
20420            match self.soft_wrap_mode(cx) {
20421                SoftWrap::Column(soft_wrap) => {
20422                    wrap_guides.push((soft_wrap as usize, true));
20423                }
20424                SoftWrap::Bounded(soft_wrap) => {
20425                    wrap_guides.push((soft_wrap as usize, true));
20426                }
20427                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20428            }
20429            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20430        }
20431
20432        wrap_guides
20433    }
20434
20435    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20436        let settings = self.buffer.read(cx).language_settings(cx);
20437        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20438        match mode {
20439            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20440                SoftWrap::None
20441            }
20442            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20443            language_settings::SoftWrap::PreferredLineLength => {
20444                SoftWrap::Column(settings.preferred_line_length)
20445            }
20446            language_settings::SoftWrap::Bounded => {
20447                SoftWrap::Bounded(settings.preferred_line_length)
20448            }
20449        }
20450    }
20451
20452    pub fn set_soft_wrap_mode(
20453        &mut self,
20454        mode: language_settings::SoftWrap,
20455
20456        cx: &mut Context<Self>,
20457    ) {
20458        self.soft_wrap_mode_override = Some(mode);
20459        cx.notify();
20460    }
20461
20462    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20463        self.hard_wrap = hard_wrap;
20464        cx.notify();
20465    }
20466
20467    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20468        self.text_style_refinement = Some(style);
20469    }
20470
20471    /// called by the Element so we know what style we were most recently rendered with.
20472    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20473        // We intentionally do not inform the display map about the minimap style
20474        // so that wrapping is not recalculated and stays consistent for the editor
20475        // and its linked minimap.
20476        if !self.mode.is_minimap() {
20477            let font = style.text.font();
20478            let font_size = style.text.font_size.to_pixels(window.rem_size());
20479            let display_map = self
20480                .placeholder_display_map
20481                .as_ref()
20482                .filter(|_| self.is_empty(cx))
20483                .unwrap_or(&self.display_map);
20484
20485            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20486        }
20487        self.style = Some(style);
20488    }
20489
20490    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20491        if self.style.is_none() {
20492            self.style = Some(self.create_style(cx));
20493        }
20494        self.style.as_ref().unwrap()
20495    }
20496
20497    // Called by the element. This method is not designed to be called outside of the editor
20498    // element's layout code because it does not notify when rewrapping is computed synchronously.
20499    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20500        if self.is_empty(cx) {
20501            self.placeholder_display_map
20502                .as_ref()
20503                .map_or(false, |display_map| {
20504                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20505                })
20506        } else {
20507            self.display_map
20508                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20509        }
20510    }
20511
20512    pub fn set_soft_wrap(&mut self) {
20513        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20514    }
20515
20516    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20517        if self.soft_wrap_mode_override.is_some() {
20518            self.soft_wrap_mode_override.take();
20519        } else {
20520            let soft_wrap = match self.soft_wrap_mode(cx) {
20521                SoftWrap::GitDiff => return,
20522                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20523                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20524                    language_settings::SoftWrap::None
20525                }
20526            };
20527            self.soft_wrap_mode_override = Some(soft_wrap);
20528        }
20529        cx.notify();
20530    }
20531
20532    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20533        let Some(workspace) = self.workspace() else {
20534            return;
20535        };
20536        let fs = workspace.read(cx).app_state().fs.clone();
20537        let current_show = TabBarSettings::get_global(cx).show;
20538        update_settings_file(fs, cx, move |setting, _| {
20539            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20540        });
20541    }
20542
20543    pub fn toggle_indent_guides(
20544        &mut self,
20545        _: &ToggleIndentGuides,
20546        _: &mut Window,
20547        cx: &mut Context<Self>,
20548    ) {
20549        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20550            self.buffer
20551                .read(cx)
20552                .language_settings(cx)
20553                .indent_guides
20554                .enabled
20555        });
20556        self.show_indent_guides = Some(!currently_enabled);
20557        cx.notify();
20558    }
20559
20560    fn should_show_indent_guides(&self) -> Option<bool> {
20561        self.show_indent_guides
20562    }
20563
20564    pub fn disable_indent_guides_for_buffer(
20565        &mut self,
20566        buffer_id: BufferId,
20567        cx: &mut Context<Self>,
20568    ) {
20569        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20570        cx.notify();
20571    }
20572
20573    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20574        self.buffers_with_disabled_indent_guides
20575            .contains(&buffer_id)
20576    }
20577
20578    pub fn toggle_line_numbers(
20579        &mut self,
20580        _: &ToggleLineNumbers,
20581        _: &mut Window,
20582        cx: &mut Context<Self>,
20583    ) {
20584        let mut editor_settings = EditorSettings::get_global(cx).clone();
20585        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20586        EditorSettings::override_global(editor_settings, cx);
20587    }
20588
20589    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20590        if let Some(show_line_numbers) = self.show_line_numbers {
20591            return show_line_numbers;
20592        }
20593        EditorSettings::get_global(cx).gutter.line_numbers
20594    }
20595
20596    pub fn relative_line_numbers(&self, cx: &App) -> RelativeLineNumbers {
20597        match (
20598            self.use_relative_line_numbers,
20599            EditorSettings::get_global(cx).relative_line_numbers,
20600        ) {
20601            (None, setting) => setting,
20602            (Some(false), _) => RelativeLineNumbers::Disabled,
20603            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20604            (Some(true), _) => RelativeLineNumbers::Enabled,
20605        }
20606    }
20607
20608    pub fn toggle_relative_line_numbers(
20609        &mut self,
20610        _: &ToggleRelativeLineNumbers,
20611        _: &mut Window,
20612        cx: &mut Context<Self>,
20613    ) {
20614        let is_relative = self.relative_line_numbers(cx);
20615        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20616    }
20617
20618    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20619        self.use_relative_line_numbers = is_relative;
20620        cx.notify();
20621    }
20622
20623    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20624        self.show_gutter = show_gutter;
20625        cx.notify();
20626    }
20627
20628    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20629        self.show_scrollbars = ScrollbarAxes {
20630            horizontal: show,
20631            vertical: show,
20632        };
20633        cx.notify();
20634    }
20635
20636    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20637        self.show_scrollbars.vertical = show;
20638        cx.notify();
20639    }
20640
20641    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20642        self.show_scrollbars.horizontal = show;
20643        cx.notify();
20644    }
20645
20646    pub fn set_minimap_visibility(
20647        &mut self,
20648        minimap_visibility: MinimapVisibility,
20649        window: &mut Window,
20650        cx: &mut Context<Self>,
20651    ) {
20652        if self.minimap_visibility != minimap_visibility {
20653            if minimap_visibility.visible() && self.minimap.is_none() {
20654                let minimap_settings = EditorSettings::get_global(cx).minimap;
20655                self.minimap =
20656                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20657            }
20658            self.minimap_visibility = minimap_visibility;
20659            cx.notify();
20660        }
20661    }
20662
20663    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20664        self.set_show_scrollbars(false, cx);
20665        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20666    }
20667
20668    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20669        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20670    }
20671
20672    /// Normally the text in full mode and auto height editors is padded on the
20673    /// left side by roughly half a character width for improved hit testing.
20674    ///
20675    /// Use this method to disable this for cases where this is not wanted (e.g.
20676    /// if you want to align the editor text with some other text above or below)
20677    /// or if you want to add this padding to single-line editors.
20678    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20679        self.offset_content = offset_content;
20680        cx.notify();
20681    }
20682
20683    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20684        self.show_line_numbers = Some(show_line_numbers);
20685        cx.notify();
20686    }
20687
20688    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20689        self.disable_expand_excerpt_buttons = true;
20690        cx.notify();
20691    }
20692
20693    pub fn set_delegate_expand_excerpts(&mut self, delegate: bool) {
20694        self.delegate_expand_excerpts = delegate;
20695    }
20696
20697    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20698        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20699        cx.notify();
20700    }
20701
20702    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20703        self.show_code_actions = Some(show_code_actions);
20704        cx.notify();
20705    }
20706
20707    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20708        self.show_runnables = Some(show_runnables);
20709        cx.notify();
20710    }
20711
20712    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20713        self.show_breakpoints = Some(show_breakpoints);
20714        cx.notify();
20715    }
20716
20717    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20718        if self.display_map.read(cx).masked != masked {
20719            self.display_map.update(cx, |map, _| map.masked = masked);
20720        }
20721        cx.notify()
20722    }
20723
20724    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20725        self.show_wrap_guides = Some(show_wrap_guides);
20726        cx.notify();
20727    }
20728
20729    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20730        self.show_indent_guides = Some(show_indent_guides);
20731        cx.notify();
20732    }
20733
20734    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20735        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20736            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20737                && let Some(dir) = file.abs_path(cx).parent()
20738            {
20739                return Some(dir.to_owned());
20740            }
20741        }
20742
20743        None
20744    }
20745
20746    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20747        self.active_excerpt(cx)?
20748            .1
20749            .read(cx)
20750            .file()
20751            .and_then(|f| f.as_local())
20752    }
20753
20754    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20755        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20756            let buffer = buffer.read(cx);
20757            if let Some(project_path) = buffer.project_path(cx) {
20758                let project = self.project()?.read(cx);
20759                project.absolute_path(&project_path, cx)
20760            } else {
20761                buffer
20762                    .file()
20763                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20764            }
20765        })
20766    }
20767
20768    pub fn reveal_in_finder(
20769        &mut self,
20770        _: &RevealInFileManager,
20771        _window: &mut Window,
20772        cx: &mut Context<Self>,
20773    ) {
20774        if let Some(target) = self.target_file(cx) {
20775            cx.reveal_path(&target.abs_path(cx));
20776        }
20777    }
20778
20779    pub fn copy_path(
20780        &mut self,
20781        _: &zed_actions::workspace::CopyPath,
20782        _window: &mut Window,
20783        cx: &mut Context<Self>,
20784    ) {
20785        if let Some(path) = self.target_file_abs_path(cx)
20786            && let Some(path) = path.to_str()
20787        {
20788            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20789        } else {
20790            cx.propagate();
20791        }
20792    }
20793
20794    pub fn copy_relative_path(
20795        &mut self,
20796        _: &zed_actions::workspace::CopyRelativePath,
20797        _window: &mut Window,
20798        cx: &mut Context<Self>,
20799    ) {
20800        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20801            let project = self.project()?.read(cx);
20802            let path = buffer.read(cx).file()?.path();
20803            let path = path.display(project.path_style(cx));
20804            Some(path)
20805        }) {
20806            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20807        } else {
20808            cx.propagate();
20809        }
20810    }
20811
20812    /// Returns the project path for the editor's buffer, if any buffer is
20813    /// opened in the editor.
20814    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20815        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20816            buffer.read(cx).project_path(cx)
20817        } else {
20818            None
20819        }
20820    }
20821
20822    // Returns true if the editor handled a go-to-line request
20823    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20824        maybe!({
20825            let breakpoint_store = self.breakpoint_store.as_ref()?;
20826
20827            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20828            else {
20829                self.clear_row_highlights::<ActiveDebugLine>();
20830                return None;
20831            };
20832
20833            let position = active_stack_frame.position;
20834            let buffer_id = position.buffer_id?;
20835            let snapshot = self
20836                .project
20837                .as_ref()?
20838                .read(cx)
20839                .buffer_for_id(buffer_id, cx)?
20840                .read(cx)
20841                .snapshot();
20842
20843            let mut handled = false;
20844            for (id, ExcerptRange { context, .. }) in
20845                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20846            {
20847                if context.start.cmp(&position, &snapshot).is_ge()
20848                    || context.end.cmp(&position, &snapshot).is_lt()
20849                {
20850                    continue;
20851                }
20852                let snapshot = self.buffer.read(cx).snapshot(cx);
20853                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20854
20855                handled = true;
20856                self.clear_row_highlights::<ActiveDebugLine>();
20857
20858                self.go_to_line::<ActiveDebugLine>(
20859                    multibuffer_anchor,
20860                    Some(cx.theme().colors().editor_debugger_active_line_background),
20861                    window,
20862                    cx,
20863                );
20864
20865                cx.notify();
20866            }
20867
20868            handled.then_some(())
20869        })
20870        .is_some()
20871    }
20872
20873    pub fn copy_file_name_without_extension(
20874        &mut self,
20875        _: &CopyFileNameWithoutExtension,
20876        _: &mut Window,
20877        cx: &mut Context<Self>,
20878    ) {
20879        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20880            let file = buffer.read(cx).file()?;
20881            file.path().file_stem()
20882        }) {
20883            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20884        }
20885    }
20886
20887    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20888        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20889            let file = buffer.read(cx).file()?;
20890            Some(file.file_name(cx))
20891        }) {
20892            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20893        }
20894    }
20895
20896    pub fn toggle_git_blame(
20897        &mut self,
20898        _: &::git::Blame,
20899        window: &mut Window,
20900        cx: &mut Context<Self>,
20901    ) {
20902        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20903
20904        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20905            self.start_git_blame(true, window, cx);
20906        }
20907
20908        cx.notify();
20909    }
20910
20911    pub fn toggle_git_blame_inline(
20912        &mut self,
20913        _: &ToggleGitBlameInline,
20914        window: &mut Window,
20915        cx: &mut Context<Self>,
20916    ) {
20917        self.toggle_git_blame_inline_internal(true, window, cx);
20918        cx.notify();
20919    }
20920
20921    pub fn open_git_blame_commit(
20922        &mut self,
20923        _: &OpenGitBlameCommit,
20924        window: &mut Window,
20925        cx: &mut Context<Self>,
20926    ) {
20927        self.open_git_blame_commit_internal(window, cx);
20928    }
20929
20930    fn open_git_blame_commit_internal(
20931        &mut self,
20932        window: &mut Window,
20933        cx: &mut Context<Self>,
20934    ) -> Option<()> {
20935        let blame = self.blame.as_ref()?;
20936        let snapshot = self.snapshot(window, cx);
20937        let cursor = self
20938            .selections
20939            .newest::<Point>(&snapshot.display_snapshot)
20940            .head();
20941        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20942        let (_, blame_entry) = blame
20943            .update(cx, |blame, cx| {
20944                blame
20945                    .blame_for_rows(
20946                        &[RowInfo {
20947                            buffer_id: Some(buffer.remote_id()),
20948                            buffer_row: Some(point.row),
20949                            ..Default::default()
20950                        }],
20951                        cx,
20952                    )
20953                    .next()
20954            })
20955            .flatten()?;
20956        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20957        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20958        let workspace = self.workspace()?.downgrade();
20959        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20960        None
20961    }
20962
20963    pub fn git_blame_inline_enabled(&self) -> bool {
20964        self.git_blame_inline_enabled
20965    }
20966
20967    pub fn toggle_selection_menu(
20968        &mut self,
20969        _: &ToggleSelectionMenu,
20970        _: &mut Window,
20971        cx: &mut Context<Self>,
20972    ) {
20973        self.show_selection_menu = self
20974            .show_selection_menu
20975            .map(|show_selections_menu| !show_selections_menu)
20976            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20977
20978        cx.notify();
20979    }
20980
20981    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20982        self.show_selection_menu
20983            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20984    }
20985
20986    fn start_git_blame(
20987        &mut self,
20988        user_triggered: bool,
20989        window: &mut Window,
20990        cx: &mut Context<Self>,
20991    ) {
20992        if let Some(project) = self.project() {
20993            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20994                && buffer.read(cx).file().is_none()
20995            {
20996                return;
20997            }
20998
20999            let focused = self.focus_handle(cx).contains_focused(window, cx);
21000
21001            let project = project.clone();
21002            let blame = cx
21003                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
21004            self.blame_subscription =
21005                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
21006            self.blame = Some(blame);
21007        }
21008    }
21009
21010    fn toggle_git_blame_inline_internal(
21011        &mut self,
21012        user_triggered: bool,
21013        window: &mut Window,
21014        cx: &mut Context<Self>,
21015    ) {
21016        if self.git_blame_inline_enabled {
21017            self.git_blame_inline_enabled = false;
21018            self.show_git_blame_inline = false;
21019            self.show_git_blame_inline_delay_task.take();
21020        } else {
21021            self.git_blame_inline_enabled = true;
21022            self.start_git_blame_inline(user_triggered, window, cx);
21023        }
21024
21025        cx.notify();
21026    }
21027
21028    fn start_git_blame_inline(
21029        &mut self,
21030        user_triggered: bool,
21031        window: &mut Window,
21032        cx: &mut Context<Self>,
21033    ) {
21034        self.start_git_blame(user_triggered, window, cx);
21035
21036        if ProjectSettings::get_global(cx)
21037            .git
21038            .inline_blame_delay()
21039            .is_some()
21040        {
21041            self.start_inline_blame_timer(window, cx);
21042        } else {
21043            self.show_git_blame_inline = true
21044        }
21045    }
21046
21047    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
21048        self.blame.as_ref()
21049    }
21050
21051    pub fn show_git_blame_gutter(&self) -> bool {
21052        self.show_git_blame_gutter
21053    }
21054
21055    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
21056        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
21057    }
21058
21059    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
21060        self.show_git_blame_inline
21061            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
21062            && !self.newest_selection_head_on_empty_line(cx)
21063            && self.has_blame_entries(cx)
21064    }
21065
21066    fn has_blame_entries(&self, cx: &App) -> bool {
21067        self.blame()
21068            .is_some_and(|blame| blame.read(cx).has_generated_entries())
21069    }
21070
21071    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
21072        let cursor_anchor = self.selections.newest_anchor().head();
21073
21074        let snapshot = self.buffer.read(cx).snapshot(cx);
21075        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
21076
21077        snapshot.line_len(buffer_row) == 0
21078    }
21079
21080    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
21081        let buffer_and_selection = maybe!({
21082            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
21083            let selection_range = selection.range();
21084
21085            let multi_buffer = self.buffer().read(cx);
21086            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21087            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
21088
21089            let (buffer, range, _) = if selection.reversed {
21090                buffer_ranges.first()
21091            } else {
21092                buffer_ranges.last()
21093            }?;
21094
21095            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
21096            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
21097
21098            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
21099                let selection = start_row_in_buffer..end_row_in_buffer;
21100
21101                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
21102            };
21103
21104            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
21105
21106            Some((
21107                multi_buffer.buffer(buffer.remote_id()).unwrap(),
21108                buffer_diff_snapshot.row_to_base_text_row(start_row_in_buffer, Bias::Left, buffer)
21109                    ..buffer_diff_snapshot.row_to_base_text_row(
21110                        end_row_in_buffer,
21111                        Bias::Left,
21112                        buffer,
21113                    ),
21114            ))
21115        });
21116
21117        let Some((buffer, selection)) = buffer_and_selection else {
21118            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
21119        };
21120
21121        let Some(project) = self.project() else {
21122            return Task::ready(Err(anyhow!("editor does not have project")));
21123        };
21124
21125        project.update(cx, |project, cx| {
21126            project.get_permalink_to_line(&buffer, selection, cx)
21127        })
21128    }
21129
21130    pub fn copy_permalink_to_line(
21131        &mut self,
21132        _: &CopyPermalinkToLine,
21133        window: &mut Window,
21134        cx: &mut Context<Self>,
21135    ) {
21136        let permalink_task = self.get_permalink_to_line(cx);
21137        let workspace = self.workspace();
21138
21139        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21140            Ok(permalink) => {
21141                cx.update(|_, cx| {
21142                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
21143                })
21144                .ok();
21145            }
21146            Err(err) => {
21147                let message = format!("Failed to copy permalink: {err}");
21148
21149                anyhow::Result::<()>::Err(err).log_err();
21150
21151                if let Some(workspace) = workspace {
21152                    workspace
21153                        .update_in(cx, |workspace, _, cx| {
21154                            struct CopyPermalinkToLine;
21155
21156                            workspace.show_toast(
21157                                Toast::new(
21158                                    NotificationId::unique::<CopyPermalinkToLine>(),
21159                                    message,
21160                                ),
21161                                cx,
21162                            )
21163                        })
21164                        .ok();
21165                }
21166            }
21167        })
21168        .detach();
21169    }
21170
21171    pub fn copy_file_location(
21172        &mut self,
21173        _: &CopyFileLocation,
21174        _: &mut Window,
21175        cx: &mut Context<Self>,
21176    ) {
21177        let selection = self
21178            .selections
21179            .newest::<Point>(&self.display_snapshot(cx))
21180            .start
21181            .row
21182            + 1;
21183        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21184            let project = self.project()?.read(cx);
21185            let file = buffer.read(cx).file()?;
21186            let path = file.path().display(project.path_style(cx));
21187
21188            Some(format!("{path}:{selection}"))
21189        }) {
21190            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
21191        }
21192    }
21193
21194    pub fn open_permalink_to_line(
21195        &mut self,
21196        _: &OpenPermalinkToLine,
21197        window: &mut Window,
21198        cx: &mut Context<Self>,
21199    ) {
21200        let permalink_task = self.get_permalink_to_line(cx);
21201        let workspace = self.workspace();
21202
21203        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21204            Ok(permalink) => {
21205                cx.update(|_, cx| {
21206                    cx.open_url(permalink.as_ref());
21207                })
21208                .ok();
21209            }
21210            Err(err) => {
21211                let message = format!("Failed to open permalink: {err}");
21212
21213                anyhow::Result::<()>::Err(err).log_err();
21214
21215                if let Some(workspace) = workspace {
21216                    workspace
21217                        .update(cx, |workspace, cx| {
21218                            struct OpenPermalinkToLine;
21219
21220                            workspace.show_toast(
21221                                Toast::new(
21222                                    NotificationId::unique::<OpenPermalinkToLine>(),
21223                                    message,
21224                                ),
21225                                cx,
21226                            )
21227                        })
21228                        .ok();
21229                }
21230            }
21231        })
21232        .detach();
21233    }
21234
21235    pub fn insert_uuid_v4(
21236        &mut self,
21237        _: &InsertUuidV4,
21238        window: &mut Window,
21239        cx: &mut Context<Self>,
21240    ) {
21241        self.insert_uuid(UuidVersion::V4, window, cx);
21242    }
21243
21244    pub fn insert_uuid_v7(
21245        &mut self,
21246        _: &InsertUuidV7,
21247        window: &mut Window,
21248        cx: &mut Context<Self>,
21249    ) {
21250        self.insert_uuid(UuidVersion::V7, window, cx);
21251    }
21252
21253    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
21254        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21255        self.transact(window, cx, |this, window, cx| {
21256            let edits = this
21257                .selections
21258                .all::<Point>(&this.display_snapshot(cx))
21259                .into_iter()
21260                .map(|selection| {
21261                    let uuid = match version {
21262                        UuidVersion::V4 => uuid::Uuid::new_v4(),
21263                        UuidVersion::V7 => uuid::Uuid::now_v7(),
21264                    };
21265
21266                    (selection.range(), uuid.to_string())
21267                });
21268            this.edit(edits, cx);
21269            this.refresh_edit_prediction(true, false, window, cx);
21270        });
21271    }
21272
21273    pub fn open_selections_in_multibuffer(
21274        &mut self,
21275        _: &OpenSelectionsInMultibuffer,
21276        window: &mut Window,
21277        cx: &mut Context<Self>,
21278    ) {
21279        let multibuffer = self.buffer.read(cx);
21280
21281        let Some(buffer) = multibuffer.as_singleton() else {
21282            return;
21283        };
21284
21285        let Some(workspace) = self.workspace() else {
21286            return;
21287        };
21288
21289        let title = multibuffer.title(cx).to_string();
21290
21291        let locations = self
21292            .selections
21293            .all_anchors(&self.display_snapshot(cx))
21294            .iter()
21295            .map(|selection| {
21296                (
21297                    buffer.clone(),
21298                    (selection.start.text_anchor..selection.end.text_anchor)
21299                        .to_point(buffer.read(cx)),
21300                )
21301            })
21302            .into_group_map();
21303
21304        cx.spawn_in(window, async move |_, cx| {
21305            workspace.update_in(cx, |workspace, window, cx| {
21306                Self::open_locations_in_multibuffer(
21307                    workspace,
21308                    locations,
21309                    format!("Selections for '{title}'"),
21310                    false,
21311                    false,
21312                    MultibufferSelectionMode::All,
21313                    window,
21314                    cx,
21315                );
21316            })
21317        })
21318        .detach();
21319    }
21320
21321    /// Adds a row highlight for the given range. If a row has multiple highlights, the
21322    /// last highlight added will be used.
21323    ///
21324    /// If the range ends at the beginning of a line, then that line will not be highlighted.
21325    pub fn highlight_rows<T: 'static>(
21326        &mut self,
21327        range: Range<Anchor>,
21328        color: Hsla,
21329        options: RowHighlightOptions,
21330        cx: &mut Context<Self>,
21331    ) {
21332        let snapshot = self.buffer().read(cx).snapshot(cx);
21333        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21334        let ix = row_highlights.binary_search_by(|highlight| {
21335            Ordering::Equal
21336                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
21337                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
21338        });
21339
21340        if let Err(mut ix) = ix {
21341            let index = post_inc(&mut self.highlight_order);
21342
21343            // If this range intersects with the preceding highlight, then merge it with
21344            // the preceding highlight. Otherwise insert a new highlight.
21345            let mut merged = false;
21346            if ix > 0 {
21347                let prev_highlight = &mut row_highlights[ix - 1];
21348                if prev_highlight
21349                    .range
21350                    .end
21351                    .cmp(&range.start, &snapshot)
21352                    .is_ge()
21353                {
21354                    ix -= 1;
21355                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
21356                        prev_highlight.range.end = range.end;
21357                    }
21358                    merged = true;
21359                    prev_highlight.index = index;
21360                    prev_highlight.color = color;
21361                    prev_highlight.options = options;
21362                }
21363            }
21364
21365            if !merged {
21366                row_highlights.insert(
21367                    ix,
21368                    RowHighlight {
21369                        range,
21370                        index,
21371                        color,
21372                        options,
21373                        type_id: TypeId::of::<T>(),
21374                    },
21375                );
21376            }
21377
21378            // If any of the following highlights intersect with this one, merge them.
21379            while let Some(next_highlight) = row_highlights.get(ix + 1) {
21380                let highlight = &row_highlights[ix];
21381                if next_highlight
21382                    .range
21383                    .start
21384                    .cmp(&highlight.range.end, &snapshot)
21385                    .is_le()
21386                {
21387                    if next_highlight
21388                        .range
21389                        .end
21390                        .cmp(&highlight.range.end, &snapshot)
21391                        .is_gt()
21392                    {
21393                        row_highlights[ix].range.end = next_highlight.range.end;
21394                    }
21395                    row_highlights.remove(ix + 1);
21396                } else {
21397                    break;
21398                }
21399            }
21400        }
21401    }
21402
21403    /// Remove any highlighted row ranges of the given type that intersect the
21404    /// given ranges.
21405    pub fn remove_highlighted_rows<T: 'static>(
21406        &mut self,
21407        ranges_to_remove: Vec<Range<Anchor>>,
21408        cx: &mut Context<Self>,
21409    ) {
21410        let snapshot = self.buffer().read(cx).snapshot(cx);
21411        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21412        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21413        row_highlights.retain(|highlight| {
21414            while let Some(range_to_remove) = ranges_to_remove.peek() {
21415                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
21416                    Ordering::Less | Ordering::Equal => {
21417                        ranges_to_remove.next();
21418                    }
21419                    Ordering::Greater => {
21420                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
21421                            Ordering::Less | Ordering::Equal => {
21422                                return false;
21423                            }
21424                            Ordering::Greater => break,
21425                        }
21426                    }
21427                }
21428            }
21429
21430            true
21431        })
21432    }
21433
21434    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
21435    pub fn clear_row_highlights<T: 'static>(&mut self) {
21436        self.highlighted_rows.remove(&TypeId::of::<T>());
21437    }
21438
21439    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
21440    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
21441        self.highlighted_rows
21442            .get(&TypeId::of::<T>())
21443            .map_or(&[] as &[_], |vec| vec.as_slice())
21444            .iter()
21445            .map(|highlight| (highlight.range.clone(), highlight.color))
21446    }
21447
21448    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
21449    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
21450    /// Allows to ignore certain kinds of highlights.
21451    pub fn highlighted_display_rows(
21452        &self,
21453        window: &mut Window,
21454        cx: &mut App,
21455    ) -> BTreeMap<DisplayRow, LineHighlight> {
21456        let snapshot = self.snapshot(window, cx);
21457        let mut used_highlight_orders = HashMap::default();
21458        self.highlighted_rows
21459            .iter()
21460            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
21461            .fold(
21462                BTreeMap::<DisplayRow, LineHighlight>::new(),
21463                |mut unique_rows, highlight| {
21464                    let start = highlight.range.start.to_display_point(&snapshot);
21465                    let end = highlight.range.end.to_display_point(&snapshot);
21466                    let start_row = start.row().0;
21467                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
21468                    {
21469                        end.row().0.saturating_sub(1)
21470                    } else {
21471                        end.row().0
21472                    };
21473                    for row in start_row..=end_row {
21474                        let used_index =
21475                            used_highlight_orders.entry(row).or_insert(highlight.index);
21476                        if highlight.index >= *used_index {
21477                            *used_index = highlight.index;
21478                            unique_rows.insert(
21479                                DisplayRow(row),
21480                                LineHighlight {
21481                                    include_gutter: highlight.options.include_gutter,
21482                                    border: None,
21483                                    background: highlight.color.into(),
21484                                    type_id: Some(highlight.type_id),
21485                                },
21486                            );
21487                        }
21488                    }
21489                    unique_rows
21490                },
21491            )
21492    }
21493
21494    pub fn highlighted_display_row_for_autoscroll(
21495        &self,
21496        snapshot: &DisplaySnapshot,
21497    ) -> Option<DisplayRow> {
21498        self.highlighted_rows
21499            .values()
21500            .flat_map(|highlighted_rows| highlighted_rows.iter())
21501            .filter_map(|highlight| {
21502                if highlight.options.autoscroll {
21503                    Some(highlight.range.start.to_display_point(snapshot).row())
21504                } else {
21505                    None
21506                }
21507            })
21508            .min()
21509    }
21510
21511    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21512        self.highlight_background::<SearchWithinRange>(
21513            ranges,
21514            |_, colors| colors.colors().editor_document_highlight_read_background,
21515            cx,
21516        )
21517    }
21518
21519    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21520        self.breadcrumb_header = Some(new_header);
21521    }
21522
21523    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21524        self.clear_background_highlights::<SearchWithinRange>(cx);
21525    }
21526
21527    pub fn highlight_background<T: 'static>(
21528        &mut self,
21529        ranges: &[Range<Anchor>],
21530        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21531        cx: &mut Context<Self>,
21532    ) {
21533        self.background_highlights.insert(
21534            HighlightKey::Type(TypeId::of::<T>()),
21535            (Arc::new(color_fetcher), Arc::from(ranges)),
21536        );
21537        self.scrollbar_marker_state.dirty = true;
21538        cx.notify();
21539    }
21540
21541    pub fn highlight_background_key<T: 'static>(
21542        &mut self,
21543        key: usize,
21544        ranges: &[Range<Anchor>],
21545        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21546        cx: &mut Context<Self>,
21547    ) {
21548        self.background_highlights.insert(
21549            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21550            (Arc::new(color_fetcher), Arc::from(ranges)),
21551        );
21552        self.scrollbar_marker_state.dirty = true;
21553        cx.notify();
21554    }
21555
21556    pub fn clear_background_highlights<T: 'static>(
21557        &mut self,
21558        cx: &mut Context<Self>,
21559    ) -> Option<BackgroundHighlight> {
21560        let text_highlights = self
21561            .background_highlights
21562            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21563        if !text_highlights.1.is_empty() {
21564            self.scrollbar_marker_state.dirty = true;
21565            cx.notify();
21566        }
21567        Some(text_highlights)
21568    }
21569
21570    pub fn highlight_gutter<T: 'static>(
21571        &mut self,
21572        ranges: impl Into<Vec<Range<Anchor>>>,
21573        color_fetcher: fn(&App) -> Hsla,
21574        cx: &mut Context<Self>,
21575    ) {
21576        self.gutter_highlights
21577            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21578        cx.notify();
21579    }
21580
21581    pub fn clear_gutter_highlights<T: 'static>(
21582        &mut self,
21583        cx: &mut Context<Self>,
21584    ) -> Option<GutterHighlight> {
21585        cx.notify();
21586        self.gutter_highlights.remove(&TypeId::of::<T>())
21587    }
21588
21589    pub fn insert_gutter_highlight<T: 'static>(
21590        &mut self,
21591        range: Range<Anchor>,
21592        color_fetcher: fn(&App) -> Hsla,
21593        cx: &mut Context<Self>,
21594    ) {
21595        let snapshot = self.buffer().read(cx).snapshot(cx);
21596        let mut highlights = self
21597            .gutter_highlights
21598            .remove(&TypeId::of::<T>())
21599            .map(|(_, highlights)| highlights)
21600            .unwrap_or_default();
21601        let ix = highlights.binary_search_by(|highlight| {
21602            Ordering::Equal
21603                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21604                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21605        });
21606        if let Err(ix) = ix {
21607            highlights.insert(ix, range);
21608        }
21609        self.gutter_highlights
21610            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21611    }
21612
21613    pub fn remove_gutter_highlights<T: 'static>(
21614        &mut self,
21615        ranges_to_remove: Vec<Range<Anchor>>,
21616        cx: &mut Context<Self>,
21617    ) {
21618        let snapshot = self.buffer().read(cx).snapshot(cx);
21619        let Some((color_fetcher, mut gutter_highlights)) =
21620            self.gutter_highlights.remove(&TypeId::of::<T>())
21621        else {
21622            return;
21623        };
21624        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21625        gutter_highlights.retain(|highlight| {
21626            while let Some(range_to_remove) = ranges_to_remove.peek() {
21627                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21628                    Ordering::Less | Ordering::Equal => {
21629                        ranges_to_remove.next();
21630                    }
21631                    Ordering::Greater => {
21632                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21633                            Ordering::Less | Ordering::Equal => {
21634                                return false;
21635                            }
21636                            Ordering::Greater => break,
21637                        }
21638                    }
21639                }
21640            }
21641
21642            true
21643        });
21644        self.gutter_highlights
21645            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21646    }
21647
21648    #[cfg(feature = "test-support")]
21649    pub fn all_text_highlights(
21650        &self,
21651        window: &mut Window,
21652        cx: &mut Context<Self>,
21653    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21654        let snapshot = self.snapshot(window, cx);
21655        self.display_map.update(cx, |display_map, _| {
21656            display_map
21657                .all_text_highlights()
21658                .map(|highlight| {
21659                    let (style, ranges) = highlight.as_ref();
21660                    (
21661                        *style,
21662                        ranges
21663                            .iter()
21664                            .map(|range| range.clone().to_display_points(&snapshot))
21665                            .collect(),
21666                    )
21667                })
21668                .collect()
21669        })
21670    }
21671
21672    #[cfg(feature = "test-support")]
21673    pub fn all_text_background_highlights(
21674        &self,
21675        window: &mut Window,
21676        cx: &mut Context<Self>,
21677    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21678        let snapshot = self.snapshot(window, cx);
21679        let buffer = &snapshot.buffer_snapshot();
21680        let start = buffer.anchor_before(MultiBufferOffset(0));
21681        let end = buffer.anchor_after(buffer.len());
21682        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21683    }
21684
21685    #[cfg(any(test, feature = "test-support"))]
21686    pub fn sorted_background_highlights_in_range(
21687        &self,
21688        search_range: Range<Anchor>,
21689        display_snapshot: &DisplaySnapshot,
21690        theme: &Theme,
21691    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21692        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21693        res.sort_by(|a, b| {
21694            a.0.start
21695                .cmp(&b.0.start)
21696                .then_with(|| a.0.end.cmp(&b.0.end))
21697                .then_with(|| a.1.cmp(&b.1))
21698        });
21699        res
21700    }
21701
21702    #[cfg(feature = "test-support")]
21703    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21704        let snapshot = self.buffer().read(cx).snapshot(cx);
21705
21706        let highlights = self
21707            .background_highlights
21708            .get(&HighlightKey::Type(TypeId::of::<
21709                items::BufferSearchHighlights,
21710            >()));
21711
21712        if let Some((_color, ranges)) = highlights {
21713            ranges
21714                .iter()
21715                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21716                .collect_vec()
21717        } else {
21718            vec![]
21719        }
21720    }
21721
21722    fn document_highlights_for_position<'a>(
21723        &'a self,
21724        position: Anchor,
21725        buffer: &'a MultiBufferSnapshot,
21726    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21727        let read_highlights = self
21728            .background_highlights
21729            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21730            .map(|h| &h.1);
21731        let write_highlights = self
21732            .background_highlights
21733            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21734            .map(|h| &h.1);
21735        let left_position = position.bias_left(buffer);
21736        let right_position = position.bias_right(buffer);
21737        read_highlights
21738            .into_iter()
21739            .chain(write_highlights)
21740            .flat_map(move |ranges| {
21741                let start_ix = match ranges.binary_search_by(|probe| {
21742                    let cmp = probe.end.cmp(&left_position, buffer);
21743                    if cmp.is_ge() {
21744                        Ordering::Greater
21745                    } else {
21746                        Ordering::Less
21747                    }
21748                }) {
21749                    Ok(i) | Err(i) => i,
21750                };
21751
21752                ranges[start_ix..]
21753                    .iter()
21754                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21755            })
21756    }
21757
21758    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21759        self.background_highlights
21760            .get(&HighlightKey::Type(TypeId::of::<T>()))
21761            .is_some_and(|(_, highlights)| !highlights.is_empty())
21762    }
21763
21764    /// Returns all background highlights for a given range.
21765    ///
21766    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21767    pub fn background_highlights_in_range(
21768        &self,
21769        search_range: Range<Anchor>,
21770        display_snapshot: &DisplaySnapshot,
21771        theme: &Theme,
21772    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21773        let mut results = Vec::new();
21774        for (color_fetcher, ranges) in self.background_highlights.values() {
21775            let start_ix = match ranges.binary_search_by(|probe| {
21776                let cmp = probe
21777                    .end
21778                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21779                if cmp.is_gt() {
21780                    Ordering::Greater
21781                } else {
21782                    Ordering::Less
21783                }
21784            }) {
21785                Ok(i) | Err(i) => i,
21786            };
21787            for (index, range) in ranges[start_ix..].iter().enumerate() {
21788                if range
21789                    .start
21790                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21791                    .is_ge()
21792                {
21793                    break;
21794                }
21795
21796                let color = color_fetcher(&(start_ix + index), theme);
21797                let start = range.start.to_display_point(display_snapshot);
21798                let end = range.end.to_display_point(display_snapshot);
21799                results.push((start..end, color))
21800            }
21801        }
21802        results
21803    }
21804
21805    pub fn gutter_highlights_in_range(
21806        &self,
21807        search_range: Range<Anchor>,
21808        display_snapshot: &DisplaySnapshot,
21809        cx: &App,
21810    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21811        let mut results = Vec::new();
21812        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21813            let color = color_fetcher(cx);
21814            let start_ix = match ranges.binary_search_by(|probe| {
21815                let cmp = probe
21816                    .end
21817                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21818                if cmp.is_gt() {
21819                    Ordering::Greater
21820                } else {
21821                    Ordering::Less
21822                }
21823            }) {
21824                Ok(i) | Err(i) => i,
21825            };
21826            for range in &ranges[start_ix..] {
21827                if range
21828                    .start
21829                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21830                    .is_ge()
21831                {
21832                    break;
21833                }
21834
21835                let start = range.start.to_display_point(display_snapshot);
21836                let end = range.end.to_display_point(display_snapshot);
21837                results.push((start..end, color))
21838            }
21839        }
21840        results
21841    }
21842
21843    /// Get the text ranges corresponding to the redaction query
21844    pub fn redacted_ranges(
21845        &self,
21846        search_range: Range<Anchor>,
21847        display_snapshot: &DisplaySnapshot,
21848        cx: &App,
21849    ) -> Vec<Range<DisplayPoint>> {
21850        display_snapshot
21851            .buffer_snapshot()
21852            .redacted_ranges(search_range, |file| {
21853                if let Some(file) = file {
21854                    file.is_private()
21855                        && EditorSettings::get(
21856                            Some(SettingsLocation {
21857                                worktree_id: file.worktree_id(cx),
21858                                path: file.path().as_ref(),
21859                            }),
21860                            cx,
21861                        )
21862                        .redact_private_values
21863                } else {
21864                    false
21865                }
21866            })
21867            .map(|range| {
21868                range.start.to_display_point(display_snapshot)
21869                    ..range.end.to_display_point(display_snapshot)
21870            })
21871            .collect()
21872    }
21873
21874    pub fn highlight_text_key<T: 'static>(
21875        &mut self,
21876        key: usize,
21877        ranges: Vec<Range<Anchor>>,
21878        style: HighlightStyle,
21879        merge: bool,
21880        cx: &mut Context<Self>,
21881    ) {
21882        self.display_map.update(cx, |map, cx| {
21883            map.highlight_text(
21884                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21885                ranges,
21886                style,
21887                merge,
21888                cx,
21889            );
21890        });
21891        cx.notify();
21892    }
21893
21894    pub fn highlight_text<T: 'static>(
21895        &mut self,
21896        ranges: Vec<Range<Anchor>>,
21897        style: HighlightStyle,
21898        cx: &mut Context<Self>,
21899    ) {
21900        self.display_map.update(cx, |map, cx| {
21901            map.highlight_text(
21902                HighlightKey::Type(TypeId::of::<T>()),
21903                ranges,
21904                style,
21905                false,
21906                cx,
21907            )
21908        });
21909        cx.notify();
21910    }
21911
21912    pub fn text_highlights<'a, T: 'static>(
21913        &'a self,
21914        cx: &'a App,
21915    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21916        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21917    }
21918
21919    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21920        let cleared = self
21921            .display_map
21922            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21923        if cleared {
21924            cx.notify();
21925        }
21926    }
21927
21928    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21929        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21930            && self.focus_handle.is_focused(window)
21931    }
21932
21933    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21934        self.show_cursor_when_unfocused = is_enabled;
21935        cx.notify();
21936    }
21937
21938    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21939        cx.notify();
21940    }
21941
21942    fn on_debug_session_event(
21943        &mut self,
21944        _session: Entity<Session>,
21945        event: &SessionEvent,
21946        cx: &mut Context<Self>,
21947    ) {
21948        if let SessionEvent::InvalidateInlineValue = event {
21949            self.refresh_inline_values(cx);
21950        }
21951    }
21952
21953    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21954        let Some(project) = self.project.clone() else {
21955            return;
21956        };
21957
21958        if !self.inline_value_cache.enabled {
21959            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21960            self.splice_inlays(&inlays, Vec::new(), cx);
21961            return;
21962        }
21963
21964        let current_execution_position = self
21965            .highlighted_rows
21966            .get(&TypeId::of::<ActiveDebugLine>())
21967            .and_then(|lines| lines.last().map(|line| line.range.end));
21968
21969        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21970            let inline_values = editor
21971                .update(cx, |editor, cx| {
21972                    let Some(current_execution_position) = current_execution_position else {
21973                        return Some(Task::ready(Ok(Vec::new())));
21974                    };
21975
21976                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21977                        let snapshot = buffer.snapshot(cx);
21978
21979                        let excerpt = snapshot.excerpt_containing(
21980                            current_execution_position..current_execution_position,
21981                        )?;
21982
21983                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21984                    })?;
21985
21986                    let range =
21987                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21988
21989                    project.inline_values(buffer, range, cx)
21990                })
21991                .ok()
21992                .flatten()?
21993                .await
21994                .context("refreshing debugger inlays")
21995                .log_err()?;
21996
21997            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21998
21999            for (buffer_id, inline_value) in inline_values
22000                .into_iter()
22001                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
22002            {
22003                buffer_inline_values
22004                    .entry(buffer_id)
22005                    .or_default()
22006                    .push(inline_value);
22007            }
22008
22009            editor
22010                .update(cx, |editor, cx| {
22011                    let snapshot = editor.buffer.read(cx).snapshot(cx);
22012                    let mut new_inlays = Vec::default();
22013
22014                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
22015                        let buffer_id = buffer_snapshot.remote_id();
22016                        buffer_inline_values
22017                            .get(&buffer_id)
22018                            .into_iter()
22019                            .flatten()
22020                            .for_each(|hint| {
22021                                let inlay = Inlay::debugger(
22022                                    post_inc(&mut editor.next_inlay_id),
22023                                    Anchor::in_buffer(excerpt_id, hint.position),
22024                                    hint.text(),
22025                                );
22026                                if !inlay.text().chars().contains(&'\n') {
22027                                    new_inlays.push(inlay);
22028                                }
22029                            });
22030                    }
22031
22032                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
22033                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
22034
22035                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
22036                })
22037                .ok()?;
22038            Some(())
22039        });
22040    }
22041
22042    fn on_buffer_event(
22043        &mut self,
22044        multibuffer: &Entity<MultiBuffer>,
22045        event: &multi_buffer::Event,
22046        window: &mut Window,
22047        cx: &mut Context<Self>,
22048    ) {
22049        match event {
22050            multi_buffer::Event::Edited { edited_buffer } => {
22051                self.scrollbar_marker_state.dirty = true;
22052                self.active_indent_guides_state.dirty = true;
22053                self.refresh_active_diagnostics(cx);
22054                self.refresh_code_actions(window, cx);
22055                self.refresh_single_line_folds(window, cx);
22056                self.refresh_matching_bracket_highlights(window, cx);
22057                if self.has_active_edit_prediction() {
22058                    self.update_visible_edit_prediction(window, cx);
22059                }
22060
22061                if let Some(buffer) = edited_buffer {
22062                    if buffer.read(cx).file().is_none() {
22063                        cx.emit(EditorEvent::TitleChanged);
22064                    }
22065
22066                    if self.project.is_some() {
22067                        let buffer_id = buffer.read(cx).remote_id();
22068                        self.register_buffer(buffer_id, cx);
22069                        self.update_lsp_data(Some(buffer_id), window, cx);
22070                        self.refresh_inlay_hints(
22071                            InlayHintRefreshReason::BufferEdited(buffer_id),
22072                            cx,
22073                        );
22074                    }
22075                }
22076
22077                cx.emit(EditorEvent::BufferEdited);
22078                cx.emit(SearchEvent::MatchesInvalidated);
22079
22080                let Some(project) = &self.project else { return };
22081                let (telemetry, is_via_ssh) = {
22082                    let project = project.read(cx);
22083                    let telemetry = project.client().telemetry().clone();
22084                    let is_via_ssh = project.is_via_remote_server();
22085                    (telemetry, is_via_ssh)
22086                };
22087                telemetry.log_edit_event("editor", is_via_ssh);
22088            }
22089            multi_buffer::Event::ExcerptsAdded {
22090                buffer,
22091                predecessor,
22092                excerpts,
22093            } => {
22094                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22095                let buffer_id = buffer.read(cx).remote_id();
22096                if self.buffer.read(cx).diff_for(buffer_id).is_none()
22097                    && let Some(project) = &self.project
22098                {
22099                    update_uncommitted_diff_for_buffer(
22100                        cx.entity(),
22101                        project,
22102                        [buffer.clone()],
22103                        self.buffer.clone(),
22104                        cx,
22105                    )
22106                    .detach();
22107                }
22108                self.update_lsp_data(Some(buffer_id), window, cx);
22109                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22110                self.colorize_brackets(false, cx);
22111                cx.emit(EditorEvent::ExcerptsAdded {
22112                    buffer: buffer.clone(),
22113                    predecessor: *predecessor,
22114                    excerpts: excerpts.clone(),
22115                });
22116            }
22117            multi_buffer::Event::ExcerptsRemoved {
22118                ids,
22119                removed_buffer_ids,
22120            } => {
22121                if let Some(inlay_hints) = &mut self.inlay_hints {
22122                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
22123                }
22124                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
22125                for buffer_id in removed_buffer_ids {
22126                    self.registered_buffers.remove(buffer_id);
22127                }
22128                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22129                cx.emit(EditorEvent::ExcerptsRemoved {
22130                    ids: ids.clone(),
22131                    removed_buffer_ids: removed_buffer_ids.clone(),
22132                });
22133            }
22134            multi_buffer::Event::ExcerptsEdited {
22135                excerpt_ids,
22136                buffer_ids,
22137            } => {
22138                self.display_map.update(cx, |map, cx| {
22139                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
22140                });
22141                cx.emit(EditorEvent::ExcerptsEdited {
22142                    ids: excerpt_ids.clone(),
22143                });
22144            }
22145            multi_buffer::Event::ExcerptsExpanded { ids } => {
22146                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22147                self.refresh_document_highlights(cx);
22148                for id in ids {
22149                    self.fetched_tree_sitter_chunks.remove(id);
22150                }
22151                self.colorize_brackets(false, cx);
22152                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
22153            }
22154            multi_buffer::Event::Reparsed(buffer_id) => {
22155                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22156                self.refresh_selected_text_highlights(true, window, cx);
22157                self.colorize_brackets(true, cx);
22158                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22159
22160                cx.emit(EditorEvent::Reparsed(*buffer_id));
22161            }
22162            multi_buffer::Event::DiffHunksToggled => {
22163                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22164            }
22165            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
22166                if !is_fresh_language {
22167                    self.registered_buffers.remove(&buffer_id);
22168                }
22169                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22170                cx.emit(EditorEvent::Reparsed(*buffer_id));
22171                cx.notify();
22172            }
22173            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
22174            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
22175            multi_buffer::Event::FileHandleChanged
22176            | multi_buffer::Event::Reloaded
22177            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
22178            multi_buffer::Event::DiagnosticsUpdated => {
22179                self.update_diagnostics_state(window, cx);
22180            }
22181            _ => {}
22182        };
22183    }
22184
22185    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
22186        if !self.diagnostics_enabled() {
22187            return;
22188        }
22189        self.refresh_active_diagnostics(cx);
22190        self.refresh_inline_diagnostics(true, window, cx);
22191        self.scrollbar_marker_state.dirty = true;
22192        cx.notify();
22193    }
22194
22195    pub fn start_temporary_diff_override(&mut self) {
22196        self.load_diff_task.take();
22197        self.temporary_diff_override = true;
22198    }
22199
22200    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
22201        self.temporary_diff_override = false;
22202        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
22203        self.buffer.update(cx, |buffer, cx| {
22204            buffer.set_all_diff_hunks_collapsed(cx);
22205        });
22206
22207        if let Some(project) = self.project.clone() {
22208            self.load_diff_task = Some(
22209                update_uncommitted_diff_for_buffer(
22210                    cx.entity(),
22211                    &project,
22212                    self.buffer.read(cx).all_buffers(),
22213                    self.buffer.clone(),
22214                    cx,
22215                )
22216                .shared(),
22217            );
22218        }
22219    }
22220
22221    fn on_display_map_changed(
22222        &mut self,
22223        _: Entity<DisplayMap>,
22224        _: &mut Window,
22225        cx: &mut Context<Self>,
22226    ) {
22227        cx.notify();
22228    }
22229
22230    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
22231        if !self.mode.is_full() {
22232            return None;
22233        }
22234
22235        let theme_settings = theme::ThemeSettings::get_global(cx);
22236        let theme = cx.theme();
22237        let accent_colors = theme.accents().clone();
22238
22239        let accent_overrides = theme_settings
22240            .theme_overrides
22241            .get(theme.name.as_ref())
22242            .map(|theme_style| &theme_style.accents)
22243            .into_iter()
22244            .flatten()
22245            .chain(
22246                theme_settings
22247                    .experimental_theme_overrides
22248                    .as_ref()
22249                    .map(|overrides| &overrides.accents)
22250                    .into_iter()
22251                    .flatten(),
22252            )
22253            .flat_map(|accent| accent.0.clone())
22254            .collect();
22255
22256        Some(AccentData {
22257            colors: accent_colors,
22258            overrides: accent_overrides,
22259        })
22260    }
22261
22262    fn fetch_applicable_language_settings(
22263        &self,
22264        cx: &App,
22265    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
22266        if !self.mode.is_full() {
22267            return HashMap::default();
22268        }
22269
22270        self.buffer().read(cx).all_buffers().into_iter().fold(
22271            HashMap::default(),
22272            |mut acc, buffer| {
22273                let buffer = buffer.read(cx);
22274                let language = buffer.language().map(|language| language.name());
22275                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
22276                    let file = buffer.file();
22277                    v.insert(language_settings(language, file, cx).into_owned());
22278                }
22279                acc
22280            },
22281        )
22282    }
22283
22284    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22285        let new_language_settings = self.fetch_applicable_language_settings(cx);
22286        let language_settings_changed = new_language_settings != self.applicable_language_settings;
22287        self.applicable_language_settings = new_language_settings;
22288
22289        let new_accents = self.fetch_accent_data(cx);
22290        let accents_changed = new_accents != self.accent_data;
22291        self.accent_data = new_accents;
22292
22293        if self.diagnostics_enabled() {
22294            let new_severity = EditorSettings::get_global(cx)
22295                .diagnostics_max_severity
22296                .unwrap_or(DiagnosticSeverity::Hint);
22297            self.set_max_diagnostics_severity(new_severity, cx);
22298        }
22299        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22300        self.update_edit_prediction_settings(cx);
22301        self.refresh_edit_prediction(true, false, window, cx);
22302        self.refresh_inline_values(cx);
22303        self.refresh_inlay_hints(
22304            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
22305                self.selections.newest_anchor().head(),
22306                &self.buffer.read(cx).snapshot(cx),
22307                cx,
22308            )),
22309            cx,
22310        );
22311
22312        let old_cursor_shape = self.cursor_shape;
22313        let old_show_breadcrumbs = self.show_breadcrumbs;
22314
22315        {
22316            let editor_settings = EditorSettings::get_global(cx);
22317            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
22318            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
22319            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
22320            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
22321        }
22322
22323        if old_cursor_shape != self.cursor_shape {
22324            cx.emit(EditorEvent::CursorShapeChanged);
22325        }
22326
22327        if old_show_breadcrumbs != self.show_breadcrumbs {
22328            cx.emit(EditorEvent::BreadcrumbsChanged);
22329        }
22330
22331        let project_settings = ProjectSettings::get_global(cx);
22332        self.buffer_serialization = self
22333            .should_serialize_buffer()
22334            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
22335
22336        if self.mode.is_full() {
22337            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
22338            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
22339            if self.show_inline_diagnostics != show_inline_diagnostics {
22340                self.show_inline_diagnostics = show_inline_diagnostics;
22341                self.refresh_inline_diagnostics(false, window, cx);
22342            }
22343
22344            if self.git_blame_inline_enabled != inline_blame_enabled {
22345                self.toggle_git_blame_inline_internal(false, window, cx);
22346            }
22347
22348            let minimap_settings = EditorSettings::get_global(cx).minimap;
22349            if self.minimap_visibility != MinimapVisibility::Disabled {
22350                if self.minimap_visibility.settings_visibility()
22351                    != minimap_settings.minimap_enabled()
22352                {
22353                    self.set_minimap_visibility(
22354                        MinimapVisibility::for_mode(self.mode(), cx),
22355                        window,
22356                        cx,
22357                    );
22358                } else if let Some(minimap_entity) = self.minimap.as_ref() {
22359                    minimap_entity.update(cx, |minimap_editor, cx| {
22360                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
22361                    })
22362                }
22363            }
22364
22365            if language_settings_changed || accents_changed {
22366                self.colorize_brackets(true, cx);
22367            }
22368
22369            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
22370                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
22371            }) {
22372                if !inlay_splice.is_empty() {
22373                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
22374                }
22375                self.refresh_colors_for_visible_range(None, window, cx);
22376            }
22377        }
22378
22379        cx.notify();
22380    }
22381
22382    pub fn set_searchable(&mut self, searchable: bool) {
22383        self.searchable = searchable;
22384    }
22385
22386    pub fn searchable(&self) -> bool {
22387        self.searchable
22388    }
22389
22390    pub fn open_excerpts_in_split(
22391        &mut self,
22392        _: &OpenExcerptsSplit,
22393        window: &mut Window,
22394        cx: &mut Context<Self>,
22395    ) {
22396        self.open_excerpts_common(None, true, window, cx)
22397    }
22398
22399    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
22400        self.open_excerpts_common(None, false, window, cx)
22401    }
22402
22403    fn open_excerpts_common(
22404        &mut self,
22405        jump_data: Option<JumpData>,
22406        split: bool,
22407        window: &mut Window,
22408        cx: &mut Context<Self>,
22409    ) {
22410        let Some(workspace) = self.workspace() else {
22411            cx.propagate();
22412            return;
22413        };
22414
22415        if self.buffer.read(cx).is_singleton() {
22416            cx.propagate();
22417            return;
22418        }
22419
22420        let mut new_selections_by_buffer = HashMap::default();
22421        match &jump_data {
22422            Some(JumpData::MultiBufferPoint {
22423                excerpt_id,
22424                position,
22425                anchor,
22426                line_offset_from_top,
22427            }) => {
22428                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22429                if let Some(buffer) = multi_buffer_snapshot
22430                    .buffer_id_for_excerpt(*excerpt_id)
22431                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
22432                {
22433                    let buffer_snapshot = buffer.read(cx).snapshot();
22434                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
22435                        language::ToPoint::to_point(anchor, &buffer_snapshot)
22436                    } else {
22437                        buffer_snapshot.clip_point(*position, Bias::Left)
22438                    };
22439                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
22440                    new_selections_by_buffer.insert(
22441                        buffer,
22442                        (
22443                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
22444                            Some(*line_offset_from_top),
22445                        ),
22446                    );
22447                }
22448            }
22449            Some(JumpData::MultiBufferRow {
22450                row,
22451                line_offset_from_top,
22452            }) => {
22453                let point = MultiBufferPoint::new(row.0, 0);
22454                if let Some((buffer, buffer_point, _)) =
22455                    self.buffer.read(cx).point_to_buffer_point(point, cx)
22456                {
22457                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
22458                    new_selections_by_buffer
22459                        .entry(buffer)
22460                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
22461                        .0
22462                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
22463                }
22464            }
22465            None => {
22466                let selections = self
22467                    .selections
22468                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
22469                let multi_buffer = self.buffer.read(cx);
22470                for selection in selections {
22471                    for (snapshot, range, _, anchor) in multi_buffer
22472                        .snapshot(cx)
22473                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
22474                    {
22475                        if let Some(anchor) = anchor {
22476                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
22477                            else {
22478                                continue;
22479                            };
22480                            let offset = text::ToOffset::to_offset(
22481                                &anchor.text_anchor,
22482                                &buffer_handle.read(cx).snapshot(),
22483                            );
22484                            let range = BufferOffset(offset)..BufferOffset(offset);
22485                            new_selections_by_buffer
22486                                .entry(buffer_handle)
22487                                .or_insert((Vec::new(), None))
22488                                .0
22489                                .push(range)
22490                        } else {
22491                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22492                            else {
22493                                continue;
22494                            };
22495                            new_selections_by_buffer
22496                                .entry(buffer_handle)
22497                                .or_insert((Vec::new(), None))
22498                                .0
22499                                .push(range)
22500                        }
22501                    }
22502                }
22503            }
22504        }
22505
22506        new_selections_by_buffer
22507            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
22508
22509        if new_selections_by_buffer.is_empty() {
22510            return;
22511        }
22512
22513        // We defer the pane interaction because we ourselves are a workspace item
22514        // and activating a new item causes the pane to call a method on us reentrantly,
22515        // which panics if we're on the stack.
22516        window.defer(cx, move |window, cx| {
22517            workspace.update(cx, |workspace, cx| {
22518                let pane = if split {
22519                    workspace.adjacent_pane(window, cx)
22520                } else {
22521                    workspace.active_pane().clone()
22522                };
22523
22524                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22525                    let buffer_read = buffer.read(cx);
22526                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22527                        (true, project::File::from_dyn(Some(file)).is_some())
22528                    } else {
22529                        (false, false)
22530                    };
22531
22532                    // If project file is none workspace.open_project_item will fail to open the excerpt
22533                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22534                    // so we check if there's a tab match in that case first
22535                    let editor = (!has_file || !is_project_file)
22536                        .then(|| {
22537                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22538                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22539                            // Instead, we try to activate the existing editor in the pane first.
22540                            let (editor, pane_item_index, pane_item_id) =
22541                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22542                                    let editor = item.downcast::<Editor>()?;
22543                                    let singleton_buffer =
22544                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22545                                    if singleton_buffer == buffer {
22546                                        Some((editor, i, item.item_id()))
22547                                    } else {
22548                                        None
22549                                    }
22550                                })?;
22551                            pane.update(cx, |pane, cx| {
22552                                pane.activate_item(pane_item_index, true, true, window, cx);
22553                                if !PreviewTabsSettings::get_global(cx)
22554                                    .enable_preview_from_multibuffer
22555                                {
22556                                    pane.unpreview_item_if_preview(pane_item_id);
22557                                }
22558                            });
22559                            Some(editor)
22560                        })
22561                        .flatten()
22562                        .unwrap_or_else(|| {
22563                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22564                                .enable_keep_preview_on_code_navigation;
22565                            let allow_new_preview =
22566                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22567                            workspace.open_project_item::<Self>(
22568                                pane.clone(),
22569                                buffer,
22570                                true,
22571                                true,
22572                                keep_old_preview,
22573                                allow_new_preview,
22574                                window,
22575                                cx,
22576                            )
22577                        });
22578
22579                    editor.update(cx, |editor, cx| {
22580                        if has_file && !is_project_file {
22581                            editor.set_read_only(true);
22582                        }
22583                        let autoscroll = match scroll_offset {
22584                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22585                            None => Autoscroll::newest(),
22586                        };
22587                        let nav_history = editor.nav_history.take();
22588                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
22589                        let Some((&excerpt_id, _, buffer_snapshot)) =
22590                            multibuffer_snapshot.as_singleton()
22591                        else {
22592                            return;
22593                        };
22594                        editor.change_selections(
22595                            SelectionEffects::scroll(autoscroll),
22596                            window,
22597                            cx,
22598                            |s| {
22599                                s.select_ranges(ranges.into_iter().map(|range| {
22600                                    let range = buffer_snapshot.anchor_before(range.start)
22601                                        ..buffer_snapshot.anchor_after(range.end);
22602                                    multibuffer_snapshot
22603                                        .anchor_range_in_excerpt(excerpt_id, range)
22604                                        .unwrap()
22605                                }));
22606                            },
22607                        );
22608                        editor.nav_history = nav_history;
22609                    });
22610                }
22611            })
22612        });
22613    }
22614
22615    // Allow opening excerpts for buffers that either belong to the current project
22616    // or represent synthetic/non-local files (e.g., git blobs). File-less buffers
22617    // are also supported so tests and other in-memory views keep working.
22618    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
22619        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some() || !file.is_local())
22620    }
22621
22622    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22623        let snapshot = self.buffer.read(cx).read(cx);
22624        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22625        Some(
22626            ranges
22627                .iter()
22628                .map(move |range| {
22629                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22630                })
22631                .collect(),
22632        )
22633    }
22634
22635    fn selection_replacement_ranges(
22636        &self,
22637        range: Range<MultiBufferOffsetUtf16>,
22638        cx: &mut App,
22639    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22640        let selections = self
22641            .selections
22642            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22643        let newest_selection = selections
22644            .iter()
22645            .max_by_key(|selection| selection.id)
22646            .unwrap();
22647        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22648        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22649        let snapshot = self.buffer.read(cx).read(cx);
22650        selections
22651            .into_iter()
22652            .map(|mut selection| {
22653                selection.start.0.0 =
22654                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22655                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22656                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22657                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22658            })
22659            .collect()
22660    }
22661
22662    fn report_editor_event(
22663        &self,
22664        reported_event: ReportEditorEvent,
22665        file_extension: Option<String>,
22666        cx: &App,
22667    ) {
22668        if cfg!(any(test, feature = "test-support")) {
22669            return;
22670        }
22671
22672        let Some(project) = &self.project else { return };
22673
22674        // If None, we are in a file without an extension
22675        let file = self
22676            .buffer
22677            .read(cx)
22678            .as_singleton()
22679            .and_then(|b| b.read(cx).file());
22680        let file_extension = file_extension.or(file
22681            .as_ref()
22682            .and_then(|file| Path::new(file.file_name(cx)).extension())
22683            .and_then(|e| e.to_str())
22684            .map(|a| a.to_string()));
22685
22686        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
22687            .map(|vim_mode| vim_mode.0)
22688            .unwrap_or(false);
22689
22690        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22691        let copilot_enabled = edit_predictions_provider
22692            == language::language_settings::EditPredictionProvider::Copilot;
22693        let copilot_enabled_for_language = self
22694            .buffer
22695            .read(cx)
22696            .language_settings(cx)
22697            .show_edit_predictions;
22698
22699        let project = project.read(cx);
22700        let event_type = reported_event.event_type();
22701
22702        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22703            telemetry::event!(
22704                event_type,
22705                type = if auto_saved {"autosave"} else {"manual"},
22706                file_extension,
22707                vim_mode,
22708                copilot_enabled,
22709                copilot_enabled_for_language,
22710                edit_predictions_provider,
22711                is_via_ssh = project.is_via_remote_server(),
22712            );
22713        } else {
22714            telemetry::event!(
22715                event_type,
22716                file_extension,
22717                vim_mode,
22718                copilot_enabled,
22719                copilot_enabled_for_language,
22720                edit_predictions_provider,
22721                is_via_ssh = project.is_via_remote_server(),
22722            );
22723        };
22724    }
22725
22726    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22727    /// with each line being an array of {text, highlight} objects.
22728    fn copy_highlight_json(
22729        &mut self,
22730        _: &CopyHighlightJson,
22731        window: &mut Window,
22732        cx: &mut Context<Self>,
22733    ) {
22734        #[derive(Serialize)]
22735        struct Chunk<'a> {
22736            text: String,
22737            highlight: Option<&'a str>,
22738        }
22739
22740        let snapshot = self.buffer.read(cx).snapshot(cx);
22741        let range = self
22742            .selected_text_range(false, window, cx)
22743            .and_then(|selection| {
22744                if selection.range.is_empty() {
22745                    None
22746                } else {
22747                    Some(
22748                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22749                            selection.range.start,
22750                        )))
22751                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22752                                selection.range.end,
22753                            ))),
22754                    )
22755                }
22756            })
22757            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22758
22759        let chunks = snapshot.chunks(range, true);
22760        let mut lines = Vec::new();
22761        let mut line: VecDeque<Chunk> = VecDeque::new();
22762
22763        let Some(style) = self.style.as_ref() else {
22764            return;
22765        };
22766
22767        for chunk in chunks {
22768            let highlight = chunk
22769                .syntax_highlight_id
22770                .and_then(|id| id.name(&style.syntax));
22771            let mut chunk_lines = chunk.text.split('\n').peekable();
22772            while let Some(text) = chunk_lines.next() {
22773                let mut merged_with_last_token = false;
22774                if let Some(last_token) = line.back_mut()
22775                    && last_token.highlight == highlight
22776                {
22777                    last_token.text.push_str(text);
22778                    merged_with_last_token = true;
22779                }
22780
22781                if !merged_with_last_token {
22782                    line.push_back(Chunk {
22783                        text: text.into(),
22784                        highlight,
22785                    });
22786                }
22787
22788                if chunk_lines.peek().is_some() {
22789                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22790                        line.pop_front();
22791                    }
22792                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22793                        line.pop_back();
22794                    }
22795
22796                    lines.push(mem::take(&mut line));
22797                }
22798            }
22799        }
22800
22801        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22802            return;
22803        };
22804        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22805    }
22806
22807    pub fn open_context_menu(
22808        &mut self,
22809        _: &OpenContextMenu,
22810        window: &mut Window,
22811        cx: &mut Context<Self>,
22812    ) {
22813        self.request_autoscroll(Autoscroll::newest(), cx);
22814        let position = self
22815            .selections
22816            .newest_display(&self.display_snapshot(cx))
22817            .start;
22818        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22819    }
22820
22821    pub fn replay_insert_event(
22822        &mut self,
22823        text: &str,
22824        relative_utf16_range: Option<Range<isize>>,
22825        window: &mut Window,
22826        cx: &mut Context<Self>,
22827    ) {
22828        if !self.input_enabled {
22829            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22830            return;
22831        }
22832        if let Some(relative_utf16_range) = relative_utf16_range {
22833            let selections = self
22834                .selections
22835                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22836            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22837                let new_ranges = selections.into_iter().map(|range| {
22838                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22839                        range
22840                            .head()
22841                            .0
22842                            .0
22843                            .saturating_add_signed(relative_utf16_range.start),
22844                    ));
22845                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22846                        range
22847                            .head()
22848                            .0
22849                            .0
22850                            .saturating_add_signed(relative_utf16_range.end),
22851                    ));
22852                    start..end
22853                });
22854                s.select_ranges(new_ranges);
22855            });
22856        }
22857
22858        self.handle_input(text, window, cx);
22859    }
22860
22861    pub fn is_focused(&self, window: &Window) -> bool {
22862        self.focus_handle.is_focused(window)
22863    }
22864
22865    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22866        cx.emit(EditorEvent::Focused);
22867
22868        if let Some(descendant) = self
22869            .last_focused_descendant
22870            .take()
22871            .and_then(|descendant| descendant.upgrade())
22872        {
22873            window.focus(&descendant, cx);
22874        } else {
22875            if let Some(blame) = self.blame.as_ref() {
22876                blame.update(cx, GitBlame::focus)
22877            }
22878
22879            self.blink_manager.update(cx, BlinkManager::enable);
22880            self.show_cursor_names(window, cx);
22881            self.buffer.update(cx, |buffer, cx| {
22882                buffer.finalize_last_transaction(cx);
22883                if self.leader_id.is_none() {
22884                    buffer.set_active_selections(
22885                        &self.selections.disjoint_anchors_arc(),
22886                        self.selections.line_mode(),
22887                        self.cursor_shape,
22888                        cx,
22889                    );
22890                }
22891            });
22892
22893            if let Some(position_map) = self.last_position_map.clone() {
22894                EditorElement::mouse_moved(
22895                    self,
22896                    &MouseMoveEvent {
22897                        position: window.mouse_position(),
22898                        pressed_button: None,
22899                        modifiers: window.modifiers(),
22900                    },
22901                    &position_map,
22902                    window,
22903                    cx,
22904                );
22905            }
22906        }
22907    }
22908
22909    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22910        cx.emit(EditorEvent::FocusedIn)
22911    }
22912
22913    fn handle_focus_out(
22914        &mut self,
22915        event: FocusOutEvent,
22916        _window: &mut Window,
22917        cx: &mut Context<Self>,
22918    ) {
22919        if event.blurred != self.focus_handle {
22920            self.last_focused_descendant = Some(event.blurred);
22921        }
22922        self.selection_drag_state = SelectionDragState::None;
22923        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22924    }
22925
22926    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22927        self.blink_manager.update(cx, BlinkManager::disable);
22928        self.buffer
22929            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22930
22931        if let Some(blame) = self.blame.as_ref() {
22932            blame.update(cx, GitBlame::blur)
22933        }
22934        if !self.hover_state.focused(window, cx) {
22935            hide_hover(self, cx);
22936        }
22937        if !self
22938            .context_menu
22939            .borrow()
22940            .as_ref()
22941            .is_some_and(|context_menu| context_menu.focused(window, cx))
22942        {
22943            self.hide_context_menu(window, cx);
22944        }
22945        self.take_active_edit_prediction(cx);
22946        cx.emit(EditorEvent::Blurred);
22947        cx.notify();
22948    }
22949
22950    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22951        let mut pending: String = window
22952            .pending_input_keystrokes()
22953            .into_iter()
22954            .flatten()
22955            .filter_map(|keystroke| keystroke.key_char.clone())
22956            .collect();
22957
22958        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22959            pending = "".to_string();
22960        }
22961
22962        let existing_pending = self
22963            .text_highlights::<PendingInput>(cx)
22964            .map(|(_, ranges)| ranges.to_vec());
22965        if existing_pending.is_none() && pending.is_empty() {
22966            return;
22967        }
22968        let transaction =
22969            self.transact(window, cx, |this, window, cx| {
22970                let selections = this
22971                    .selections
22972                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22973                let edits = selections
22974                    .iter()
22975                    .map(|selection| (selection.end..selection.end, pending.clone()));
22976                this.edit(edits, cx);
22977                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22978                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22979                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22980                    }));
22981                });
22982                if let Some(existing_ranges) = existing_pending {
22983                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22984                    this.edit(edits, cx);
22985                }
22986            });
22987
22988        let snapshot = self.snapshot(window, cx);
22989        let ranges = self
22990            .selections
22991            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22992            .into_iter()
22993            .map(|selection| {
22994                snapshot.buffer_snapshot().anchor_after(selection.end)
22995                    ..snapshot
22996                        .buffer_snapshot()
22997                        .anchor_before(selection.end + pending.len())
22998            })
22999            .collect();
23000
23001        if pending.is_empty() {
23002            self.clear_highlights::<PendingInput>(cx);
23003        } else {
23004            self.highlight_text::<PendingInput>(
23005                ranges,
23006                HighlightStyle {
23007                    underline: Some(UnderlineStyle {
23008                        thickness: px(1.),
23009                        color: None,
23010                        wavy: false,
23011                    }),
23012                    ..Default::default()
23013                },
23014                cx,
23015            );
23016        }
23017
23018        self.ime_transaction = self.ime_transaction.or(transaction);
23019        if let Some(transaction) = self.ime_transaction {
23020            self.buffer.update(cx, |buffer, cx| {
23021                buffer.group_until_transaction(transaction, cx);
23022            });
23023        }
23024
23025        if self.text_highlights::<PendingInput>(cx).is_none() {
23026            self.ime_transaction.take();
23027        }
23028    }
23029
23030    pub fn register_action_renderer(
23031        &mut self,
23032        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
23033    ) -> Subscription {
23034        let id = self.next_editor_action_id.post_inc();
23035        self.editor_actions
23036            .borrow_mut()
23037            .insert(id, Box::new(listener));
23038
23039        let editor_actions = self.editor_actions.clone();
23040        Subscription::new(move || {
23041            editor_actions.borrow_mut().remove(&id);
23042        })
23043    }
23044
23045    pub fn register_action<A: Action>(
23046        &mut self,
23047        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
23048    ) -> Subscription {
23049        let id = self.next_editor_action_id.post_inc();
23050        let listener = Arc::new(listener);
23051        self.editor_actions.borrow_mut().insert(
23052            id,
23053            Box::new(move |_, window, _| {
23054                let listener = listener.clone();
23055                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
23056                    let action = action.downcast_ref().unwrap();
23057                    if phase == DispatchPhase::Bubble {
23058                        listener(action, window, cx)
23059                    }
23060                })
23061            }),
23062        );
23063
23064        let editor_actions = self.editor_actions.clone();
23065        Subscription::new(move || {
23066            editor_actions.borrow_mut().remove(&id);
23067        })
23068    }
23069
23070    pub fn file_header_size(&self) -> u32 {
23071        FILE_HEADER_HEIGHT
23072    }
23073
23074    pub fn restore(
23075        &mut self,
23076        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
23077        window: &mut Window,
23078        cx: &mut Context<Self>,
23079    ) {
23080        self.buffer().update(cx, |multi_buffer, cx| {
23081            for (buffer_id, changes) in revert_changes {
23082                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
23083                    buffer.update(cx, |buffer, cx| {
23084                        buffer.edit(
23085                            changes
23086                                .into_iter()
23087                                .map(|(range, text)| (range, text.to_string())),
23088                            None,
23089                            cx,
23090                        );
23091                    });
23092                }
23093            }
23094        });
23095        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23096            selections.refresh()
23097        });
23098    }
23099
23100    pub fn to_pixel_point(
23101        &mut self,
23102        source: multi_buffer::Anchor,
23103        editor_snapshot: &EditorSnapshot,
23104        window: &mut Window,
23105        cx: &App,
23106    ) -> Option<gpui::Point<Pixels>> {
23107        let source_point = source.to_display_point(editor_snapshot);
23108        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
23109    }
23110
23111    pub fn display_to_pixel_point(
23112        &mut self,
23113        source: DisplayPoint,
23114        editor_snapshot: &EditorSnapshot,
23115        window: &mut Window,
23116        cx: &App,
23117    ) -> Option<gpui::Point<Pixels>> {
23118        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
23119        let text_layout_details = self.text_layout_details(window);
23120        let scroll_top = text_layout_details
23121            .scroll_anchor
23122            .scroll_position(editor_snapshot)
23123            .y;
23124
23125        if source.row().as_f64() < scroll_top.floor() {
23126            return None;
23127        }
23128        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
23129        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
23130        Some(gpui::Point::new(source_x, source_y))
23131    }
23132
23133    pub fn has_visible_completions_menu(&self) -> bool {
23134        !self.edit_prediction_preview_is_active()
23135            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
23136                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
23137            })
23138    }
23139
23140    pub fn register_addon<T: Addon>(&mut self, instance: T) {
23141        if self.mode.is_minimap() {
23142            return;
23143        }
23144        self.addons
23145            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
23146    }
23147
23148    pub fn unregister_addon<T: Addon>(&mut self) {
23149        self.addons.remove(&std::any::TypeId::of::<T>());
23150    }
23151
23152    pub fn addon<T: Addon>(&self) -> Option<&T> {
23153        let type_id = std::any::TypeId::of::<T>();
23154        self.addons
23155            .get(&type_id)
23156            .and_then(|item| item.to_any().downcast_ref::<T>())
23157    }
23158
23159    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
23160        let type_id = std::any::TypeId::of::<T>();
23161        self.addons
23162            .get_mut(&type_id)
23163            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
23164    }
23165
23166    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
23167        let text_layout_details = self.text_layout_details(window);
23168        let style = &text_layout_details.editor_style;
23169        let font_id = window.text_system().resolve_font(&style.text.font());
23170        let font_size = style.text.font_size.to_pixels(window.rem_size());
23171        let line_height = style.text.line_height_in_pixels(window.rem_size());
23172        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
23173        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
23174
23175        CharacterDimensions {
23176            em_width,
23177            em_advance,
23178            line_height,
23179        }
23180    }
23181
23182    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
23183        self.load_diff_task.clone()
23184    }
23185
23186    fn read_metadata_from_db(
23187        &mut self,
23188        item_id: u64,
23189        workspace_id: WorkspaceId,
23190        window: &mut Window,
23191        cx: &mut Context<Editor>,
23192    ) {
23193        if self.buffer_kind(cx) == ItemBufferKind::Singleton
23194            && !self.mode.is_minimap()
23195            && WorkspaceSettings::get(None, cx).restore_on_startup
23196                != RestoreOnStartupBehavior::EmptyTab
23197        {
23198            let buffer_snapshot = OnceCell::new();
23199
23200            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
23201                && !folds.is_empty()
23202            {
23203                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23204                self.fold_ranges(
23205                    folds
23206                        .into_iter()
23207                        .map(|(start, end)| {
23208                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23209                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23210                        })
23211                        .collect(),
23212                    false,
23213                    window,
23214                    cx,
23215                );
23216            }
23217
23218            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
23219                && !selections.is_empty()
23220            {
23221                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23222                // skip adding the initial selection to selection history
23223                self.selection_history.mode = SelectionHistoryMode::Skipping;
23224                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23225                    s.select_ranges(selections.into_iter().map(|(start, end)| {
23226                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23227                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23228                    }));
23229                });
23230                self.selection_history.mode = SelectionHistoryMode::Normal;
23231            };
23232        }
23233
23234        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
23235    }
23236
23237    fn update_lsp_data(
23238        &mut self,
23239        for_buffer: Option<BufferId>,
23240        window: &mut Window,
23241        cx: &mut Context<'_, Self>,
23242    ) {
23243        self.pull_diagnostics(for_buffer, window, cx);
23244        self.refresh_colors_for_visible_range(for_buffer, window, cx);
23245    }
23246
23247    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
23248        if self.ignore_lsp_data() {
23249            return;
23250        }
23251        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
23252            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
23253        }
23254    }
23255
23256    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
23257        if self.ignore_lsp_data() {
23258            return;
23259        }
23260
23261        if !self.registered_buffers.contains_key(&buffer_id)
23262            && let Some(project) = self.project.as_ref()
23263        {
23264            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
23265                project.update(cx, |project, cx| {
23266                    self.registered_buffers.insert(
23267                        buffer_id,
23268                        project.register_buffer_with_language_servers(&buffer, cx),
23269                    );
23270                });
23271            } else {
23272                self.registered_buffers.remove(&buffer_id);
23273            }
23274        }
23275    }
23276
23277    fn ignore_lsp_data(&self) -> bool {
23278        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
23279        // skip any LSP updates for it.
23280        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
23281    }
23282
23283    fn create_style(&self, cx: &App) -> EditorStyle {
23284        let settings = ThemeSettings::get_global(cx);
23285
23286        let mut text_style = match self.mode {
23287            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23288                color: cx.theme().colors().editor_foreground,
23289                font_family: settings.ui_font.family.clone(),
23290                font_features: settings.ui_font.features.clone(),
23291                font_fallbacks: settings.ui_font.fallbacks.clone(),
23292                font_size: rems(0.875).into(),
23293                font_weight: settings.ui_font.weight,
23294                line_height: relative(settings.buffer_line_height.value()),
23295                ..Default::default()
23296            },
23297            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23298                color: cx.theme().colors().editor_foreground,
23299                font_family: settings.buffer_font.family.clone(),
23300                font_features: settings.buffer_font.features.clone(),
23301                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23302                font_size: settings.buffer_font_size(cx).into(),
23303                font_weight: settings.buffer_font.weight,
23304                line_height: relative(settings.buffer_line_height.value()),
23305                ..Default::default()
23306            },
23307        };
23308        if let Some(text_style_refinement) = &self.text_style_refinement {
23309            text_style.refine(text_style_refinement)
23310        }
23311
23312        let background = match self.mode {
23313            EditorMode::SingleLine => cx.theme().system().transparent,
23314            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23315            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23316            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23317        };
23318
23319        EditorStyle {
23320            background,
23321            border: cx.theme().colors().border,
23322            local_player: cx.theme().players().local(),
23323            text: text_style,
23324            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23325            syntax: cx.theme().syntax().clone(),
23326            status: cx.theme().status().clone(),
23327            inlay_hints_style: make_inlay_hints_style(cx),
23328            edit_prediction_styles: make_suggestion_styles(cx),
23329            unnecessary_code_fade: settings.unnecessary_code_fade,
23330            show_underlines: self.diagnostics_enabled(),
23331        }
23332    }
23333}
23334
23335fn edit_for_markdown_paste<'a>(
23336    buffer: &MultiBufferSnapshot,
23337    range: Range<MultiBufferOffset>,
23338    to_insert: &'a str,
23339    url: Option<url::Url>,
23340) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
23341    if url.is_none() {
23342        return (range, Cow::Borrowed(to_insert));
23343    };
23344
23345    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
23346
23347    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
23348        Cow::Borrowed(to_insert)
23349    } else {
23350        Cow::Owned(format!("[{old_text}]({to_insert})"))
23351    };
23352    (range, new_text)
23353}
23354
23355fn process_completion_for_edit(
23356    completion: &Completion,
23357    intent: CompletionIntent,
23358    buffer: &Entity<Buffer>,
23359    cursor_position: &text::Anchor,
23360    cx: &mut Context<Editor>,
23361) -> CompletionEdit {
23362    let buffer = buffer.read(cx);
23363    let buffer_snapshot = buffer.snapshot();
23364    let (snippet, new_text) = if completion.is_snippet() {
23365        let mut snippet_source = completion.new_text.clone();
23366        // Workaround for typescript language server issues so that methods don't expand within
23367        // strings and functions with type expressions. The previous point is used because the query
23368        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
23369        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
23370        let previous_point = if previous_point.column > 0 {
23371            cursor_position.to_previous_offset(&buffer_snapshot)
23372        } else {
23373            cursor_position.to_offset(&buffer_snapshot)
23374        };
23375        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
23376            && scope.prefers_label_for_snippet_in_completion()
23377            && let Some(label) = completion.label()
23378            && matches!(
23379                completion.kind(),
23380                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
23381            )
23382        {
23383            snippet_source = label;
23384        }
23385        match Snippet::parse(&snippet_source).log_err() {
23386            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
23387            None => (None, completion.new_text.clone()),
23388        }
23389    } else {
23390        (None, completion.new_text.clone())
23391    };
23392
23393    let mut range_to_replace = {
23394        let replace_range = &completion.replace_range;
23395        if let CompletionSource::Lsp {
23396            insert_range: Some(insert_range),
23397            ..
23398        } = &completion.source
23399        {
23400            debug_assert_eq!(
23401                insert_range.start, replace_range.start,
23402                "insert_range and replace_range should start at the same position"
23403            );
23404            debug_assert!(
23405                insert_range
23406                    .start
23407                    .cmp(cursor_position, &buffer_snapshot)
23408                    .is_le(),
23409                "insert_range should start before or at cursor position"
23410            );
23411            debug_assert!(
23412                replace_range
23413                    .start
23414                    .cmp(cursor_position, &buffer_snapshot)
23415                    .is_le(),
23416                "replace_range should start before or at cursor position"
23417            );
23418
23419            let should_replace = match intent {
23420                CompletionIntent::CompleteWithInsert => false,
23421                CompletionIntent::CompleteWithReplace => true,
23422                CompletionIntent::Complete | CompletionIntent::Compose => {
23423                    let insert_mode =
23424                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
23425                            .completions
23426                            .lsp_insert_mode;
23427                    match insert_mode {
23428                        LspInsertMode::Insert => false,
23429                        LspInsertMode::Replace => true,
23430                        LspInsertMode::ReplaceSubsequence => {
23431                            let mut text_to_replace = buffer.chars_for_range(
23432                                buffer.anchor_before(replace_range.start)
23433                                    ..buffer.anchor_after(replace_range.end),
23434                            );
23435                            let mut current_needle = text_to_replace.next();
23436                            for haystack_ch in completion.label.text.chars() {
23437                                if let Some(needle_ch) = current_needle
23438                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
23439                                {
23440                                    current_needle = text_to_replace.next();
23441                                }
23442                            }
23443                            current_needle.is_none()
23444                        }
23445                        LspInsertMode::ReplaceSuffix => {
23446                            if replace_range
23447                                .end
23448                                .cmp(cursor_position, &buffer_snapshot)
23449                                .is_gt()
23450                            {
23451                                let range_after_cursor = *cursor_position..replace_range.end;
23452                                let text_after_cursor = buffer
23453                                    .text_for_range(
23454                                        buffer.anchor_before(range_after_cursor.start)
23455                                            ..buffer.anchor_after(range_after_cursor.end),
23456                                    )
23457                                    .collect::<String>()
23458                                    .to_ascii_lowercase();
23459                                completion
23460                                    .label
23461                                    .text
23462                                    .to_ascii_lowercase()
23463                                    .ends_with(&text_after_cursor)
23464                            } else {
23465                                true
23466                            }
23467                        }
23468                    }
23469                }
23470            };
23471
23472            if should_replace {
23473                replace_range.clone()
23474            } else {
23475                insert_range.clone()
23476            }
23477        } else {
23478            replace_range.clone()
23479        }
23480    };
23481
23482    if range_to_replace
23483        .end
23484        .cmp(cursor_position, &buffer_snapshot)
23485        .is_lt()
23486    {
23487        range_to_replace.end = *cursor_position;
23488    }
23489
23490    let replace_range = range_to_replace.to_offset(buffer);
23491    CompletionEdit {
23492        new_text,
23493        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
23494        snippet,
23495    }
23496}
23497
23498struct CompletionEdit {
23499    new_text: String,
23500    replace_range: Range<BufferOffset>,
23501    snippet: Option<Snippet>,
23502}
23503
23504fn comment_delimiter_for_newline(
23505    start_point: &Point,
23506    buffer: &MultiBufferSnapshot,
23507    language: &LanguageScope,
23508) -> Option<Arc<str>> {
23509    let delimiters = language.line_comment_prefixes();
23510    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
23511    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23512
23513    let num_of_whitespaces = snapshot
23514        .chars_for_range(range.clone())
23515        .take_while(|c| c.is_whitespace())
23516        .count();
23517    let comment_candidate = snapshot
23518        .chars_for_range(range.clone())
23519        .skip(num_of_whitespaces)
23520        .take(max_len_of_delimiter)
23521        .collect::<String>();
23522    let (delimiter, trimmed_len) = delimiters
23523        .iter()
23524        .filter_map(|delimiter| {
23525            let prefix = delimiter.trim_end();
23526            if comment_candidate.starts_with(prefix) {
23527                Some((delimiter, prefix.len()))
23528            } else {
23529                None
23530            }
23531        })
23532        .max_by_key(|(_, len)| *len)?;
23533
23534    if let Some(BlockCommentConfig {
23535        start: block_start, ..
23536    }) = language.block_comment()
23537    {
23538        let block_start_trimmed = block_start.trim_end();
23539        if block_start_trimmed.starts_with(delimiter.trim_end()) {
23540            let line_content = snapshot
23541                .chars_for_range(range)
23542                .skip(num_of_whitespaces)
23543                .take(block_start_trimmed.len())
23544                .collect::<String>();
23545
23546            if line_content.starts_with(block_start_trimmed) {
23547                return None;
23548            }
23549        }
23550    }
23551
23552    let cursor_is_placed_after_comment_marker =
23553        num_of_whitespaces + trimmed_len <= start_point.column as usize;
23554    if cursor_is_placed_after_comment_marker {
23555        Some(delimiter.clone())
23556    } else {
23557        None
23558    }
23559}
23560
23561fn documentation_delimiter_for_newline(
23562    start_point: &Point,
23563    buffer: &MultiBufferSnapshot,
23564    language: &LanguageScope,
23565    newline_config: &mut NewlineConfig,
23566) -> Option<Arc<str>> {
23567    let BlockCommentConfig {
23568        start: start_tag,
23569        end: end_tag,
23570        prefix: delimiter,
23571        tab_size: len,
23572    } = language.documentation_comment()?;
23573    let is_within_block_comment = buffer
23574        .language_scope_at(*start_point)
23575        .is_some_and(|scope| scope.override_name() == Some("comment"));
23576    if !is_within_block_comment {
23577        return None;
23578    }
23579
23580    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23581
23582    let num_of_whitespaces = snapshot
23583        .chars_for_range(range.clone())
23584        .take_while(|c| c.is_whitespace())
23585        .count();
23586
23587    // 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.
23588    let column = start_point.column;
23589    let cursor_is_after_start_tag = {
23590        let start_tag_len = start_tag.len();
23591        let start_tag_line = snapshot
23592            .chars_for_range(range.clone())
23593            .skip(num_of_whitespaces)
23594            .take(start_tag_len)
23595            .collect::<String>();
23596        if start_tag_line.starts_with(start_tag.as_ref()) {
23597            num_of_whitespaces + start_tag_len <= column as usize
23598        } else {
23599            false
23600        }
23601    };
23602
23603    let cursor_is_after_delimiter = {
23604        let delimiter_trim = delimiter.trim_end();
23605        let delimiter_line = snapshot
23606            .chars_for_range(range.clone())
23607            .skip(num_of_whitespaces)
23608            .take(delimiter_trim.len())
23609            .collect::<String>();
23610        if delimiter_line.starts_with(delimiter_trim) {
23611            num_of_whitespaces + delimiter_trim.len() <= column as usize
23612        } else {
23613            false
23614        }
23615    };
23616
23617    let mut needs_extra_line = false;
23618    let mut extra_line_additional_indent = IndentSize::spaces(0);
23619
23620    let cursor_is_before_end_tag_if_exists = {
23621        let mut char_position = 0u32;
23622        let mut end_tag_offset = None;
23623
23624        'outer: for chunk in snapshot.text_for_range(range) {
23625            if let Some(byte_pos) = chunk.find(&**end_tag) {
23626                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
23627                end_tag_offset = Some(char_position + chars_before_match);
23628                break 'outer;
23629            }
23630            char_position += chunk.chars().count() as u32;
23631        }
23632
23633        if let Some(end_tag_offset) = end_tag_offset {
23634            let cursor_is_before_end_tag = column <= end_tag_offset;
23635            if cursor_is_after_start_tag {
23636                if cursor_is_before_end_tag {
23637                    needs_extra_line = true;
23638                }
23639                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
23640                if cursor_is_at_start_of_end_tag {
23641                    extra_line_additional_indent.len = *len;
23642                }
23643            }
23644            cursor_is_before_end_tag
23645        } else {
23646            true
23647        }
23648    };
23649
23650    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
23651        && cursor_is_before_end_tag_if_exists
23652    {
23653        let additional_indent = if cursor_is_after_start_tag {
23654            IndentSize::spaces(*len)
23655        } else {
23656            IndentSize::spaces(0)
23657        };
23658
23659        *newline_config = NewlineConfig::Newline {
23660            additional_indent,
23661            extra_line_additional_indent: if needs_extra_line {
23662                Some(extra_line_additional_indent)
23663            } else {
23664                None
23665            },
23666            prevent_auto_indent: true,
23667        };
23668        Some(delimiter.clone())
23669    } else {
23670        None
23671    }
23672}
23673
23674const ORDERED_LIST_MAX_MARKER_LEN: usize = 16;
23675
23676fn list_delimiter_for_newline(
23677    start_point: &Point,
23678    buffer: &MultiBufferSnapshot,
23679    language: &LanguageScope,
23680    newline_config: &mut NewlineConfig,
23681) -> Option<Arc<str>> {
23682    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
23683
23684    let num_of_whitespaces = snapshot
23685        .chars_for_range(range.clone())
23686        .take_while(|c| c.is_whitespace())
23687        .count();
23688
23689    let task_list_entries: Vec<_> = language
23690        .task_list()
23691        .into_iter()
23692        .flat_map(|config| {
23693            config
23694                .prefixes
23695                .iter()
23696                .map(|prefix| (prefix.as_ref(), config.continuation.as_ref()))
23697        })
23698        .collect();
23699    let unordered_list_entries: Vec<_> = language
23700        .unordered_list()
23701        .iter()
23702        .map(|marker| (marker.as_ref(), marker.as_ref()))
23703        .collect();
23704
23705    let all_entries: Vec<_> = task_list_entries
23706        .into_iter()
23707        .chain(unordered_list_entries)
23708        .collect();
23709
23710    if let Some(max_prefix_len) = all_entries.iter().map(|(p, _)| p.len()).max() {
23711        let candidate: String = snapshot
23712            .chars_for_range(range.clone())
23713            .skip(num_of_whitespaces)
23714            .take(max_prefix_len)
23715            .collect();
23716
23717        if let Some((prefix, continuation)) = all_entries
23718            .iter()
23719            .filter(|(prefix, _)| candidate.starts_with(*prefix))
23720            .max_by_key(|(prefix, _)| prefix.len())
23721        {
23722            let end_of_prefix = num_of_whitespaces + prefix.len();
23723            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
23724            let has_content_after_marker = snapshot
23725                .chars_for_range(range)
23726                .skip(end_of_prefix)
23727                .any(|c| !c.is_whitespace());
23728
23729            if has_content_after_marker && cursor_is_after_prefix {
23730                return Some((*continuation).into());
23731            }
23732
23733            if start_point.column as usize == end_of_prefix {
23734                if num_of_whitespaces == 0 {
23735                    *newline_config = NewlineConfig::ClearCurrentLine;
23736                } else {
23737                    *newline_config = NewlineConfig::UnindentCurrentLine {
23738                        continuation: (*continuation).into(),
23739                    };
23740                }
23741            }
23742
23743            return None;
23744        }
23745    }
23746
23747    let candidate: String = snapshot
23748        .chars_for_range(range.clone())
23749        .skip(num_of_whitespaces)
23750        .take(ORDERED_LIST_MAX_MARKER_LEN)
23751        .collect();
23752
23753    for ordered_config in language.ordered_list() {
23754        let regex = match Regex::new(&ordered_config.pattern) {
23755            Ok(r) => r,
23756            Err(_) => continue,
23757        };
23758
23759        if let Some(captures) = regex.captures(&candidate) {
23760            let full_match = captures.get(0)?;
23761            let marker_len = full_match.len();
23762            let end_of_prefix = num_of_whitespaces + marker_len;
23763            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
23764
23765            let has_content_after_marker = snapshot
23766                .chars_for_range(range)
23767                .skip(end_of_prefix)
23768                .any(|c| !c.is_whitespace());
23769
23770            if has_content_after_marker && cursor_is_after_prefix {
23771                let number: u32 = captures.get(1)?.as_str().parse().ok()?;
23772                let continuation = ordered_config
23773                    .format
23774                    .replace("{1}", &(number + 1).to_string());
23775                return Some(continuation.into());
23776            }
23777
23778            if start_point.column as usize == end_of_prefix {
23779                let continuation = ordered_config.format.replace("{1}", "1");
23780                if num_of_whitespaces == 0 {
23781                    *newline_config = NewlineConfig::ClearCurrentLine;
23782                } else {
23783                    *newline_config = NewlineConfig::UnindentCurrentLine {
23784                        continuation: continuation.into(),
23785                    };
23786                }
23787            }
23788
23789            return None;
23790        }
23791    }
23792
23793    None
23794}
23795
23796fn is_list_prefix_row(
23797    row: MultiBufferRow,
23798    buffer: &MultiBufferSnapshot,
23799    language: &LanguageScope,
23800) -> bool {
23801    let Some((snapshot, range)) = buffer.buffer_line_for_row(row) else {
23802        return false;
23803    };
23804
23805    let num_of_whitespaces = snapshot
23806        .chars_for_range(range.clone())
23807        .take_while(|c| c.is_whitespace())
23808        .count();
23809
23810    let task_list_prefixes: Vec<_> = language
23811        .task_list()
23812        .into_iter()
23813        .flat_map(|config| {
23814            config
23815                .prefixes
23816                .iter()
23817                .map(|p| p.as_ref())
23818                .collect::<Vec<_>>()
23819        })
23820        .collect();
23821    let unordered_list_markers: Vec<_> = language
23822        .unordered_list()
23823        .iter()
23824        .map(|marker| marker.as_ref())
23825        .collect();
23826    let all_prefixes: Vec<_> = task_list_prefixes
23827        .into_iter()
23828        .chain(unordered_list_markers)
23829        .collect();
23830    if let Some(max_prefix_len) = all_prefixes.iter().map(|p| p.len()).max() {
23831        let candidate: String = snapshot
23832            .chars_for_range(range.clone())
23833            .skip(num_of_whitespaces)
23834            .take(max_prefix_len)
23835            .collect();
23836        if all_prefixes
23837            .iter()
23838            .any(|prefix| candidate.starts_with(*prefix))
23839        {
23840            return true;
23841        }
23842    }
23843
23844    let ordered_list_candidate: String = snapshot
23845        .chars_for_range(range)
23846        .skip(num_of_whitespaces)
23847        .take(ORDERED_LIST_MAX_MARKER_LEN)
23848        .collect();
23849    for ordered_config in language.ordered_list() {
23850        let regex = match Regex::new(&ordered_config.pattern) {
23851            Ok(r) => r,
23852            Err(_) => continue,
23853        };
23854        if let Some(captures) = regex.captures(&ordered_list_candidate) {
23855            return captures.get(0).is_some();
23856        }
23857    }
23858
23859    false
23860}
23861
23862#[derive(Debug)]
23863enum NewlineConfig {
23864    /// Insert newline with optional additional indent and optional extra blank line
23865    Newline {
23866        additional_indent: IndentSize,
23867        extra_line_additional_indent: Option<IndentSize>,
23868        prevent_auto_indent: bool,
23869    },
23870    /// Clear the current line
23871    ClearCurrentLine,
23872    /// Unindent the current line and add continuation
23873    UnindentCurrentLine { continuation: Arc<str> },
23874}
23875
23876impl NewlineConfig {
23877    fn has_extra_line(&self) -> bool {
23878        matches!(
23879            self,
23880            Self::Newline {
23881                extra_line_additional_indent: Some(_),
23882                ..
23883            }
23884        )
23885    }
23886
23887    fn insert_extra_newline_brackets(
23888        buffer: &MultiBufferSnapshot,
23889        range: Range<MultiBufferOffset>,
23890        language: &language::LanguageScope,
23891    ) -> bool {
23892        let leading_whitespace_len = buffer
23893            .reversed_chars_at(range.start)
23894            .take_while(|c| c.is_whitespace() && *c != '\n')
23895            .map(|c| c.len_utf8())
23896            .sum::<usize>();
23897        let trailing_whitespace_len = buffer
23898            .chars_at(range.end)
23899            .take_while(|c| c.is_whitespace() && *c != '\n')
23900            .map(|c| c.len_utf8())
23901            .sum::<usize>();
23902        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
23903
23904        language.brackets().any(|(pair, enabled)| {
23905            let pair_start = pair.start.trim_end();
23906            let pair_end = pair.end.trim_start();
23907
23908            enabled
23909                && pair.newline
23910                && buffer.contains_str_at(range.end, pair_end)
23911                && buffer.contains_str_at(
23912                    range.start.saturating_sub_usize(pair_start.len()),
23913                    pair_start,
23914                )
23915        })
23916    }
23917
23918    fn insert_extra_newline_tree_sitter(
23919        buffer: &MultiBufferSnapshot,
23920        range: Range<MultiBufferOffset>,
23921    ) -> bool {
23922        let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
23923            [(buffer, range, _)] => (*buffer, range.clone()),
23924            _ => return false,
23925        };
23926        let pair = {
23927            let mut result: Option<BracketMatch<usize>> = None;
23928
23929            for pair in buffer
23930                .all_bracket_ranges(range.start.0..range.end.0)
23931                .filter(move |pair| {
23932                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
23933                })
23934            {
23935                let len = pair.close_range.end - pair.open_range.start;
23936
23937                if let Some(existing) = &result {
23938                    let existing_len = existing.close_range.end - existing.open_range.start;
23939                    if len > existing_len {
23940                        continue;
23941                    }
23942                }
23943
23944                result = Some(pair);
23945            }
23946
23947            result
23948        };
23949        let Some(pair) = pair else {
23950            return false;
23951        };
23952        pair.newline_only
23953            && buffer
23954                .chars_for_range(pair.open_range.end..range.start.0)
23955                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
23956                .all(|c| c.is_whitespace() && c != '\n')
23957    }
23958}
23959
23960fn update_uncommitted_diff_for_buffer(
23961    editor: Entity<Editor>,
23962    project: &Entity<Project>,
23963    buffers: impl IntoIterator<Item = Entity<Buffer>>,
23964    buffer: Entity<MultiBuffer>,
23965    cx: &mut App,
23966) -> Task<()> {
23967    let mut tasks = Vec::new();
23968    project.update(cx, |project, cx| {
23969        for buffer in buffers {
23970            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
23971                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
23972            }
23973        }
23974    });
23975    cx.spawn(async move |cx| {
23976        let diffs = future::join_all(tasks).await;
23977        if editor
23978            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
23979            .unwrap_or(false)
23980        {
23981            return;
23982        }
23983
23984        buffer
23985            .update(cx, |buffer, cx| {
23986                for diff in diffs.into_iter().flatten() {
23987                    buffer.add_diff(diff, cx);
23988                }
23989            })
23990            .ok();
23991    })
23992}
23993
23994fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
23995    let tab_size = tab_size.get() as usize;
23996    let mut width = offset;
23997
23998    for ch in text.chars() {
23999        width += if ch == '\t' {
24000            tab_size - (width % tab_size)
24001        } else {
24002            1
24003        };
24004    }
24005
24006    width - offset
24007}
24008
24009#[cfg(test)]
24010mod tests {
24011    use super::*;
24012
24013    #[test]
24014    fn test_string_size_with_expanded_tabs() {
24015        let nz = |val| NonZeroU32::new(val).unwrap();
24016        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
24017        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
24018        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
24019        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
24020        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
24021        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
24022        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
24023        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
24024    }
24025}
24026
24027/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
24028struct WordBreakingTokenizer<'a> {
24029    input: &'a str,
24030}
24031
24032impl<'a> WordBreakingTokenizer<'a> {
24033    fn new(input: &'a str) -> Self {
24034        Self { input }
24035    }
24036}
24037
24038fn is_char_ideographic(ch: char) -> bool {
24039    use unicode_script::Script::*;
24040    use unicode_script::UnicodeScript;
24041    matches!(ch.script(), Han | Tangut | Yi)
24042}
24043
24044fn is_grapheme_ideographic(text: &str) -> bool {
24045    text.chars().any(is_char_ideographic)
24046}
24047
24048fn is_grapheme_whitespace(text: &str) -> bool {
24049    text.chars().any(|x| x.is_whitespace())
24050}
24051
24052fn should_stay_with_preceding_ideograph(text: &str) -> bool {
24053    text.chars()
24054        .next()
24055        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
24056}
24057
24058#[derive(PartialEq, Eq, Debug, Clone, Copy)]
24059enum WordBreakToken<'a> {
24060    Word { token: &'a str, grapheme_len: usize },
24061    InlineWhitespace { token: &'a str, grapheme_len: usize },
24062    Newline,
24063}
24064
24065impl<'a> Iterator for WordBreakingTokenizer<'a> {
24066    /// Yields a span, the count of graphemes in the token, and whether it was
24067    /// whitespace. Note that it also breaks at word boundaries.
24068    type Item = WordBreakToken<'a>;
24069
24070    fn next(&mut self) -> Option<Self::Item> {
24071        use unicode_segmentation::UnicodeSegmentation;
24072        if self.input.is_empty() {
24073            return None;
24074        }
24075
24076        let mut iter = self.input.graphemes(true).peekable();
24077        let mut offset = 0;
24078        let mut grapheme_len = 0;
24079        if let Some(first_grapheme) = iter.next() {
24080            let is_newline = first_grapheme == "\n";
24081            let is_whitespace = is_grapheme_whitespace(first_grapheme);
24082            offset += first_grapheme.len();
24083            grapheme_len += 1;
24084            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
24085                if let Some(grapheme) = iter.peek().copied()
24086                    && should_stay_with_preceding_ideograph(grapheme)
24087                {
24088                    offset += grapheme.len();
24089                    grapheme_len += 1;
24090                }
24091            } else {
24092                let mut words = self.input[offset..].split_word_bound_indices().peekable();
24093                let mut next_word_bound = words.peek().copied();
24094                if next_word_bound.is_some_and(|(i, _)| i == 0) {
24095                    next_word_bound = words.next();
24096                }
24097                while let Some(grapheme) = iter.peek().copied() {
24098                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
24099                        break;
24100                    };
24101                    if is_grapheme_whitespace(grapheme) != is_whitespace
24102                        || (grapheme == "\n") != is_newline
24103                    {
24104                        break;
24105                    };
24106                    offset += grapheme.len();
24107                    grapheme_len += 1;
24108                    iter.next();
24109                }
24110            }
24111            let token = &self.input[..offset];
24112            self.input = &self.input[offset..];
24113            if token == "\n" {
24114                Some(WordBreakToken::Newline)
24115            } else if is_whitespace {
24116                Some(WordBreakToken::InlineWhitespace {
24117                    token,
24118                    grapheme_len,
24119                })
24120            } else {
24121                Some(WordBreakToken::Word {
24122                    token,
24123                    grapheme_len,
24124                })
24125            }
24126        } else {
24127            None
24128        }
24129    }
24130}
24131
24132#[test]
24133fn test_word_breaking_tokenizer() {
24134    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
24135        ("", &[]),
24136        ("  ", &[whitespace("  ", 2)]),
24137        ("Ʒ", &[word("Ʒ", 1)]),
24138        ("Ǽ", &[word("Ǽ", 1)]),
24139        ("", &[word("", 1)]),
24140        ("⋑⋑", &[word("⋑⋑", 2)]),
24141        (
24142            "原理,进而",
24143            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
24144        ),
24145        (
24146            "hello world",
24147            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
24148        ),
24149        (
24150            "hello, world",
24151            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
24152        ),
24153        (
24154            "  hello world",
24155            &[
24156                whitespace("  ", 2),
24157                word("hello", 5),
24158                whitespace(" ", 1),
24159                word("world", 5),
24160            ],
24161        ),
24162        (
24163            "这是什么 \n 钢笔",
24164            &[
24165                word("", 1),
24166                word("", 1),
24167                word("", 1),
24168                word("", 1),
24169                whitespace(" ", 1),
24170                newline(),
24171                whitespace(" ", 1),
24172                word("", 1),
24173                word("", 1),
24174            ],
24175        ),
24176        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
24177    ];
24178
24179    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
24180        WordBreakToken::Word {
24181            token,
24182            grapheme_len,
24183        }
24184    }
24185
24186    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
24187        WordBreakToken::InlineWhitespace {
24188            token,
24189            grapheme_len,
24190        }
24191    }
24192
24193    fn newline() -> WordBreakToken<'static> {
24194        WordBreakToken::Newline
24195    }
24196
24197    for (input, result) in tests {
24198        assert_eq!(
24199            WordBreakingTokenizer::new(input)
24200                .collect::<Vec<_>>()
24201                .as_slice(),
24202            *result,
24203        );
24204    }
24205}
24206
24207fn wrap_with_prefix(
24208    first_line_prefix: String,
24209    subsequent_lines_prefix: String,
24210    unwrapped_text: String,
24211    wrap_column: usize,
24212    tab_size: NonZeroU32,
24213    preserve_existing_whitespace: bool,
24214) -> String {
24215    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
24216    let subsequent_lines_prefix_len =
24217        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
24218    let mut wrapped_text = String::new();
24219    let mut current_line = first_line_prefix;
24220    let mut is_first_line = true;
24221
24222    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
24223    let mut current_line_len = first_line_prefix_len;
24224    let mut in_whitespace = false;
24225    for token in tokenizer {
24226        let have_preceding_whitespace = in_whitespace;
24227        match token {
24228            WordBreakToken::Word {
24229                token,
24230                grapheme_len,
24231            } => {
24232                in_whitespace = false;
24233                let current_prefix_len = if is_first_line {
24234                    first_line_prefix_len
24235                } else {
24236                    subsequent_lines_prefix_len
24237                };
24238                if current_line_len + grapheme_len > wrap_column
24239                    && current_line_len != current_prefix_len
24240                {
24241                    wrapped_text.push_str(current_line.trim_end());
24242                    wrapped_text.push('\n');
24243                    is_first_line = false;
24244                    current_line = subsequent_lines_prefix.clone();
24245                    current_line_len = subsequent_lines_prefix_len;
24246                }
24247                current_line.push_str(token);
24248                current_line_len += grapheme_len;
24249            }
24250            WordBreakToken::InlineWhitespace {
24251                mut token,
24252                mut grapheme_len,
24253            } => {
24254                in_whitespace = true;
24255                if have_preceding_whitespace && !preserve_existing_whitespace {
24256                    continue;
24257                }
24258                if !preserve_existing_whitespace {
24259                    // Keep a single whitespace grapheme as-is
24260                    if let Some(first) =
24261                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
24262                    {
24263                        token = first;
24264                    } else {
24265                        token = " ";
24266                    }
24267                    grapheme_len = 1;
24268                }
24269                let current_prefix_len = if is_first_line {
24270                    first_line_prefix_len
24271                } else {
24272                    subsequent_lines_prefix_len
24273                };
24274                if current_line_len + grapheme_len > wrap_column {
24275                    wrapped_text.push_str(current_line.trim_end());
24276                    wrapped_text.push('\n');
24277                    is_first_line = false;
24278                    current_line = subsequent_lines_prefix.clone();
24279                    current_line_len = subsequent_lines_prefix_len;
24280                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
24281                    current_line.push_str(token);
24282                    current_line_len += grapheme_len;
24283                }
24284            }
24285            WordBreakToken::Newline => {
24286                in_whitespace = true;
24287                let current_prefix_len = if is_first_line {
24288                    first_line_prefix_len
24289                } else {
24290                    subsequent_lines_prefix_len
24291                };
24292                if preserve_existing_whitespace {
24293                    wrapped_text.push_str(current_line.trim_end());
24294                    wrapped_text.push('\n');
24295                    is_first_line = false;
24296                    current_line = subsequent_lines_prefix.clone();
24297                    current_line_len = subsequent_lines_prefix_len;
24298                } else if have_preceding_whitespace {
24299                    continue;
24300                } else if current_line_len + 1 > wrap_column
24301                    && current_line_len != current_prefix_len
24302                {
24303                    wrapped_text.push_str(current_line.trim_end());
24304                    wrapped_text.push('\n');
24305                    is_first_line = false;
24306                    current_line = subsequent_lines_prefix.clone();
24307                    current_line_len = subsequent_lines_prefix_len;
24308                } else if current_line_len != current_prefix_len {
24309                    current_line.push(' ');
24310                    current_line_len += 1;
24311                }
24312            }
24313        }
24314    }
24315
24316    if !current_line.is_empty() {
24317        wrapped_text.push_str(&current_line);
24318    }
24319    wrapped_text
24320}
24321
24322#[test]
24323fn test_wrap_with_prefix() {
24324    assert_eq!(
24325        wrap_with_prefix(
24326            "# ".to_string(),
24327            "# ".to_string(),
24328            "abcdefg".to_string(),
24329            4,
24330            NonZeroU32::new(4).unwrap(),
24331            false,
24332        ),
24333        "# abcdefg"
24334    );
24335    assert_eq!(
24336        wrap_with_prefix(
24337            "".to_string(),
24338            "".to_string(),
24339            "\thello world".to_string(),
24340            8,
24341            NonZeroU32::new(4).unwrap(),
24342            false,
24343        ),
24344        "hello\nworld"
24345    );
24346    assert_eq!(
24347        wrap_with_prefix(
24348            "// ".to_string(),
24349            "// ".to_string(),
24350            "xx \nyy zz aa bb cc".to_string(),
24351            12,
24352            NonZeroU32::new(4).unwrap(),
24353            false,
24354        ),
24355        "// xx yy zz\n// aa bb cc"
24356    );
24357    assert_eq!(
24358        wrap_with_prefix(
24359            String::new(),
24360            String::new(),
24361            "这是什么 \n 钢笔".to_string(),
24362            3,
24363            NonZeroU32::new(4).unwrap(),
24364            false,
24365        ),
24366        "这是什\n么 钢\n"
24367    );
24368    assert_eq!(
24369        wrap_with_prefix(
24370            String::new(),
24371            String::new(),
24372            format!("foo{}bar", '\u{2009}'), // thin space
24373            80,
24374            NonZeroU32::new(4).unwrap(),
24375            false,
24376        ),
24377        format!("foo{}bar", '\u{2009}')
24378    );
24379}
24380
24381pub trait CollaborationHub {
24382    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
24383    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
24384    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
24385}
24386
24387impl CollaborationHub for Entity<Project> {
24388    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
24389        self.read(cx).collaborators()
24390    }
24391
24392    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
24393        self.read(cx).user_store().read(cx).participant_indices()
24394    }
24395
24396    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
24397        let this = self.read(cx);
24398        let user_ids = this.collaborators().values().map(|c| c.user_id);
24399        this.user_store().read(cx).participant_names(user_ids, cx)
24400    }
24401}
24402
24403pub trait SemanticsProvider {
24404    fn hover(
24405        &self,
24406        buffer: &Entity<Buffer>,
24407        position: text::Anchor,
24408        cx: &mut App,
24409    ) -> Option<Task<Option<Vec<project::Hover>>>>;
24410
24411    fn inline_values(
24412        &self,
24413        buffer_handle: Entity<Buffer>,
24414        range: Range<text::Anchor>,
24415        cx: &mut App,
24416    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
24417
24418    fn applicable_inlay_chunks(
24419        &self,
24420        buffer: &Entity<Buffer>,
24421        ranges: &[Range<text::Anchor>],
24422        cx: &mut App,
24423    ) -> Vec<Range<BufferRow>>;
24424
24425    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
24426
24427    fn inlay_hints(
24428        &self,
24429        invalidate: InvalidationStrategy,
24430        buffer: Entity<Buffer>,
24431        ranges: Vec<Range<text::Anchor>>,
24432        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24433        cx: &mut App,
24434    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
24435
24436    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
24437
24438    fn document_highlights(
24439        &self,
24440        buffer: &Entity<Buffer>,
24441        position: text::Anchor,
24442        cx: &mut App,
24443    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
24444
24445    fn definitions(
24446        &self,
24447        buffer: &Entity<Buffer>,
24448        position: text::Anchor,
24449        kind: GotoDefinitionKind,
24450        cx: &mut App,
24451    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
24452
24453    fn range_for_rename(
24454        &self,
24455        buffer: &Entity<Buffer>,
24456        position: text::Anchor,
24457        cx: &mut App,
24458    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
24459
24460    fn perform_rename(
24461        &self,
24462        buffer: &Entity<Buffer>,
24463        position: text::Anchor,
24464        new_name: String,
24465        cx: &mut App,
24466    ) -> Option<Task<Result<ProjectTransaction>>>;
24467}
24468
24469pub trait CompletionProvider {
24470    fn completions(
24471        &self,
24472        excerpt_id: ExcerptId,
24473        buffer: &Entity<Buffer>,
24474        buffer_position: text::Anchor,
24475        trigger: CompletionContext,
24476        window: &mut Window,
24477        cx: &mut Context<Editor>,
24478    ) -> Task<Result<Vec<CompletionResponse>>>;
24479
24480    fn resolve_completions(
24481        &self,
24482        _buffer: Entity<Buffer>,
24483        _completion_indices: Vec<usize>,
24484        _completions: Rc<RefCell<Box<[Completion]>>>,
24485        _cx: &mut Context<Editor>,
24486    ) -> Task<Result<bool>> {
24487        Task::ready(Ok(false))
24488    }
24489
24490    fn apply_additional_edits_for_completion(
24491        &self,
24492        _buffer: Entity<Buffer>,
24493        _completions: Rc<RefCell<Box<[Completion]>>>,
24494        _completion_index: usize,
24495        _push_to_history: bool,
24496        _cx: &mut Context<Editor>,
24497    ) -> Task<Result<Option<language::Transaction>>> {
24498        Task::ready(Ok(None))
24499    }
24500
24501    fn is_completion_trigger(
24502        &self,
24503        buffer: &Entity<Buffer>,
24504        position: language::Anchor,
24505        text: &str,
24506        trigger_in_words: bool,
24507        cx: &mut Context<Editor>,
24508    ) -> bool;
24509
24510    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
24511
24512    fn sort_completions(&self) -> bool {
24513        true
24514    }
24515
24516    fn filter_completions(&self) -> bool {
24517        true
24518    }
24519
24520    fn show_snippets(&self) -> bool {
24521        false
24522    }
24523}
24524
24525pub trait CodeActionProvider {
24526    fn id(&self) -> Arc<str>;
24527
24528    fn code_actions(
24529        &self,
24530        buffer: &Entity<Buffer>,
24531        range: Range<text::Anchor>,
24532        window: &mut Window,
24533        cx: &mut App,
24534    ) -> Task<Result<Vec<CodeAction>>>;
24535
24536    fn apply_code_action(
24537        &self,
24538        buffer_handle: Entity<Buffer>,
24539        action: CodeAction,
24540        excerpt_id: ExcerptId,
24541        push_to_history: bool,
24542        window: &mut Window,
24543        cx: &mut App,
24544    ) -> Task<Result<ProjectTransaction>>;
24545}
24546
24547impl CodeActionProvider for Entity<Project> {
24548    fn id(&self) -> Arc<str> {
24549        "project".into()
24550    }
24551
24552    fn code_actions(
24553        &self,
24554        buffer: &Entity<Buffer>,
24555        range: Range<text::Anchor>,
24556        _window: &mut Window,
24557        cx: &mut App,
24558    ) -> Task<Result<Vec<CodeAction>>> {
24559        self.update(cx, |project, cx| {
24560            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
24561            let code_actions = project.code_actions(buffer, range, None, cx);
24562            cx.background_spawn(async move {
24563                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
24564                Ok(code_lens_actions
24565                    .context("code lens fetch")?
24566                    .into_iter()
24567                    .flatten()
24568                    .chain(
24569                        code_actions
24570                            .context("code action fetch")?
24571                            .into_iter()
24572                            .flatten(),
24573                    )
24574                    .collect())
24575            })
24576        })
24577    }
24578
24579    fn apply_code_action(
24580        &self,
24581        buffer_handle: Entity<Buffer>,
24582        action: CodeAction,
24583        _excerpt_id: ExcerptId,
24584        push_to_history: bool,
24585        _window: &mut Window,
24586        cx: &mut App,
24587    ) -> Task<Result<ProjectTransaction>> {
24588        self.update(cx, |project, cx| {
24589            project.apply_code_action(buffer_handle, action, push_to_history, cx)
24590        })
24591    }
24592}
24593
24594fn snippet_completions(
24595    project: &Project,
24596    buffer: &Entity<Buffer>,
24597    buffer_anchor: text::Anchor,
24598    classifier: CharClassifier,
24599    cx: &mut App,
24600) -> Task<Result<CompletionResponse>> {
24601    let languages = buffer.read(cx).languages_at(buffer_anchor);
24602    let snippet_store = project.snippets().read(cx);
24603
24604    let scopes: Vec<_> = languages
24605        .iter()
24606        .filter_map(|language| {
24607            let language_name = language.lsp_id();
24608            let snippets = snippet_store.snippets_for(Some(language_name), cx);
24609
24610            if snippets.is_empty() {
24611                None
24612            } else {
24613                Some((language.default_scope(), snippets))
24614            }
24615        })
24616        .collect();
24617
24618    if scopes.is_empty() {
24619        return Task::ready(Ok(CompletionResponse {
24620            completions: vec![],
24621            display_options: CompletionDisplayOptions::default(),
24622            is_incomplete: false,
24623        }));
24624    }
24625
24626    let snapshot = buffer.read(cx).text_snapshot();
24627    let executor = cx.background_executor().clone();
24628
24629    cx.background_spawn(async move {
24630        let is_word_char = |c| classifier.is_word(c);
24631
24632        let mut is_incomplete = false;
24633        let mut completions: Vec<Completion> = Vec::new();
24634
24635        const MAX_PREFIX_LEN: usize = 128;
24636        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
24637        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
24638        let window_start = snapshot.clip_offset(window_start, Bias::Left);
24639
24640        let max_buffer_window: String = snapshot
24641            .text_for_range(window_start..buffer_offset)
24642            .collect();
24643
24644        if max_buffer_window.is_empty() {
24645            return Ok(CompletionResponse {
24646                completions: vec![],
24647                display_options: CompletionDisplayOptions::default(),
24648                is_incomplete: true,
24649            });
24650        }
24651
24652        for (_scope, snippets) in scopes.into_iter() {
24653            // Sort snippets by word count to match longer snippet prefixes first.
24654            let mut sorted_snippet_candidates = snippets
24655                .iter()
24656                .enumerate()
24657                .flat_map(|(snippet_ix, snippet)| {
24658                    snippet
24659                        .prefix
24660                        .iter()
24661                        .enumerate()
24662                        .map(move |(prefix_ix, prefix)| {
24663                            let word_count =
24664                                snippet_candidate_suffixes(prefix, is_word_char).count();
24665                            ((snippet_ix, prefix_ix), prefix, word_count)
24666                        })
24667                })
24668                .collect_vec();
24669            sorted_snippet_candidates
24670                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
24671
24672            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
24673
24674            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
24675                .take(
24676                    sorted_snippet_candidates
24677                        .first()
24678                        .map(|(_, _, word_count)| *word_count)
24679                        .unwrap_or_default(),
24680                )
24681                .collect_vec();
24682
24683            const MAX_RESULTS: usize = 100;
24684            // Each match also remembers how many characters from the buffer it consumed
24685            let mut matches: Vec<(StringMatch, usize)> = vec![];
24686
24687            let mut snippet_list_cutoff_index = 0;
24688            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
24689                let word_count = buffer_index + 1;
24690                // Increase `snippet_list_cutoff_index` until we have all of the
24691                // snippets with sufficiently many words.
24692                while sorted_snippet_candidates
24693                    .get(snippet_list_cutoff_index)
24694                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
24695                        *snippet_word_count >= word_count
24696                    })
24697                {
24698                    snippet_list_cutoff_index += 1;
24699                }
24700
24701                // Take only the candidates with at least `word_count` many words
24702                let snippet_candidates_at_word_len =
24703                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
24704
24705                let candidates = snippet_candidates_at_word_len
24706                    .iter()
24707                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
24708                    .enumerate() // index in `sorted_snippet_candidates`
24709                    // First char must match
24710                    .filter(|(_ix, prefix)| {
24711                        itertools::equal(
24712                            prefix
24713                                .chars()
24714                                .next()
24715                                .into_iter()
24716                                .flat_map(|c| c.to_lowercase()),
24717                            buffer_window
24718                                .chars()
24719                                .next()
24720                                .into_iter()
24721                                .flat_map(|c| c.to_lowercase()),
24722                        )
24723                    })
24724                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
24725                    .collect::<Vec<StringMatchCandidate>>();
24726
24727                matches.extend(
24728                    fuzzy::match_strings(
24729                        &candidates,
24730                        &buffer_window,
24731                        buffer_window.chars().any(|c| c.is_uppercase()),
24732                        true,
24733                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
24734                        &Default::default(),
24735                        executor.clone(),
24736                    )
24737                    .await
24738                    .into_iter()
24739                    .map(|string_match| (string_match, buffer_window.len())),
24740                );
24741
24742                if matches.len() >= MAX_RESULTS {
24743                    break;
24744                }
24745            }
24746
24747            let to_lsp = |point: &text::Anchor| {
24748                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
24749                point_to_lsp(end)
24750            };
24751            let lsp_end = to_lsp(&buffer_anchor);
24752
24753            if matches.len() >= MAX_RESULTS {
24754                is_incomplete = true;
24755            }
24756
24757            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
24758                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
24759                    sorted_snippet_candidates[string_match.candidate_id];
24760                let snippet = &snippets[snippet_index];
24761                let start = buffer_offset - buffer_window_len;
24762                let start = snapshot.anchor_before(start);
24763                let range = start..buffer_anchor;
24764                let lsp_start = to_lsp(&start);
24765                let lsp_range = lsp::Range {
24766                    start: lsp_start,
24767                    end: lsp_end,
24768                };
24769                Completion {
24770                    replace_range: range,
24771                    new_text: snippet.body.clone(),
24772                    source: CompletionSource::Lsp {
24773                        insert_range: None,
24774                        server_id: LanguageServerId(usize::MAX),
24775                        resolved: true,
24776                        lsp_completion: Box::new(lsp::CompletionItem {
24777                            label: snippet.prefix.first().unwrap().clone(),
24778                            kind: Some(CompletionItemKind::SNIPPET),
24779                            label_details: snippet.description.as_ref().map(|description| {
24780                                lsp::CompletionItemLabelDetails {
24781                                    detail: Some(description.clone()),
24782                                    description: None,
24783                                }
24784                            }),
24785                            insert_text_format: Some(InsertTextFormat::SNIPPET),
24786                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
24787                                lsp::InsertReplaceEdit {
24788                                    new_text: snippet.body.clone(),
24789                                    insert: lsp_range,
24790                                    replace: lsp_range,
24791                                },
24792                            )),
24793                            filter_text: Some(snippet.body.clone()),
24794                            sort_text: Some(char::MAX.to_string()),
24795                            ..lsp::CompletionItem::default()
24796                        }),
24797                        lsp_defaults: None,
24798                    },
24799                    label: CodeLabel {
24800                        text: matching_prefix.clone(),
24801                        runs: Vec::new(),
24802                        filter_range: 0..matching_prefix.len(),
24803                    },
24804                    icon_path: None,
24805                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
24806                        single_line: snippet.name.clone().into(),
24807                        plain_text: snippet
24808                            .description
24809                            .clone()
24810                            .map(|description| description.into()),
24811                    }),
24812                    insert_text_mode: None,
24813                    confirm: None,
24814                    match_start: Some(start),
24815                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
24816                }
24817            }));
24818        }
24819
24820        Ok(CompletionResponse {
24821            completions,
24822            display_options: CompletionDisplayOptions::default(),
24823            is_incomplete,
24824        })
24825    })
24826}
24827
24828impl CompletionProvider for Entity<Project> {
24829    fn completions(
24830        &self,
24831        _excerpt_id: ExcerptId,
24832        buffer: &Entity<Buffer>,
24833        buffer_position: text::Anchor,
24834        options: CompletionContext,
24835        _window: &mut Window,
24836        cx: &mut Context<Editor>,
24837    ) -> Task<Result<Vec<CompletionResponse>>> {
24838        self.update(cx, |project, cx| {
24839            let task = project.completions(buffer, buffer_position, options, cx);
24840            cx.background_spawn(task)
24841        })
24842    }
24843
24844    fn resolve_completions(
24845        &self,
24846        buffer: Entity<Buffer>,
24847        completion_indices: Vec<usize>,
24848        completions: Rc<RefCell<Box<[Completion]>>>,
24849        cx: &mut Context<Editor>,
24850    ) -> Task<Result<bool>> {
24851        self.update(cx, |project, cx| {
24852            project.lsp_store().update(cx, |lsp_store, cx| {
24853                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
24854            })
24855        })
24856    }
24857
24858    fn apply_additional_edits_for_completion(
24859        &self,
24860        buffer: Entity<Buffer>,
24861        completions: Rc<RefCell<Box<[Completion]>>>,
24862        completion_index: usize,
24863        push_to_history: bool,
24864        cx: &mut Context<Editor>,
24865    ) -> Task<Result<Option<language::Transaction>>> {
24866        self.update(cx, |project, cx| {
24867            project.lsp_store().update(cx, |lsp_store, cx| {
24868                lsp_store.apply_additional_edits_for_completion(
24869                    buffer,
24870                    completions,
24871                    completion_index,
24872                    push_to_history,
24873                    cx,
24874                )
24875            })
24876        })
24877    }
24878
24879    fn is_completion_trigger(
24880        &self,
24881        buffer: &Entity<Buffer>,
24882        position: language::Anchor,
24883        text: &str,
24884        trigger_in_words: bool,
24885        cx: &mut Context<Editor>,
24886    ) -> bool {
24887        let mut chars = text.chars();
24888        let char = if let Some(char) = chars.next() {
24889            char
24890        } else {
24891            return false;
24892        };
24893        if chars.next().is_some() {
24894            return false;
24895        }
24896
24897        let buffer = buffer.read(cx);
24898        let snapshot = buffer.snapshot();
24899        let classifier = snapshot
24900            .char_classifier_at(position)
24901            .scope_context(Some(CharScopeContext::Completion));
24902        if trigger_in_words && classifier.is_word(char) {
24903            return true;
24904        }
24905
24906        buffer.completion_triggers().contains(text)
24907    }
24908
24909    fn show_snippets(&self) -> bool {
24910        true
24911    }
24912}
24913
24914impl SemanticsProvider for Entity<Project> {
24915    fn hover(
24916        &self,
24917        buffer: &Entity<Buffer>,
24918        position: text::Anchor,
24919        cx: &mut App,
24920    ) -> Option<Task<Option<Vec<project::Hover>>>> {
24921        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
24922    }
24923
24924    fn document_highlights(
24925        &self,
24926        buffer: &Entity<Buffer>,
24927        position: text::Anchor,
24928        cx: &mut App,
24929    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
24930        Some(self.update(cx, |project, cx| {
24931            project.document_highlights(buffer, position, cx)
24932        }))
24933    }
24934
24935    fn definitions(
24936        &self,
24937        buffer: &Entity<Buffer>,
24938        position: text::Anchor,
24939        kind: GotoDefinitionKind,
24940        cx: &mut App,
24941    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
24942        Some(self.update(cx, |project, cx| match kind {
24943            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
24944            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
24945            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
24946            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
24947        }))
24948    }
24949
24950    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
24951        self.update(cx, |project, cx| {
24952            if project
24953                .active_debug_session(cx)
24954                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
24955            {
24956                return true;
24957            }
24958
24959            buffer.update(cx, |buffer, cx| {
24960                project.any_language_server_supports_inlay_hints(buffer, cx)
24961            })
24962        })
24963    }
24964
24965    fn inline_values(
24966        &self,
24967        buffer_handle: Entity<Buffer>,
24968        range: Range<text::Anchor>,
24969        cx: &mut App,
24970    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
24971        self.update(cx, |project, cx| {
24972            let (session, active_stack_frame) = project.active_debug_session(cx)?;
24973
24974            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
24975        })
24976    }
24977
24978    fn applicable_inlay_chunks(
24979        &self,
24980        buffer: &Entity<Buffer>,
24981        ranges: &[Range<text::Anchor>],
24982        cx: &mut App,
24983    ) -> Vec<Range<BufferRow>> {
24984        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24985            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
24986        })
24987    }
24988
24989    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
24990        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
24991            lsp_store.invalidate_inlay_hints(for_buffers)
24992        });
24993    }
24994
24995    fn inlay_hints(
24996        &self,
24997        invalidate: InvalidationStrategy,
24998        buffer: Entity<Buffer>,
24999        ranges: Vec<Range<text::Anchor>>,
25000        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
25001        cx: &mut App,
25002    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
25003        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
25004            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
25005        }))
25006    }
25007
25008    fn range_for_rename(
25009        &self,
25010        buffer: &Entity<Buffer>,
25011        position: text::Anchor,
25012        cx: &mut App,
25013    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
25014        Some(self.update(cx, |project, cx| {
25015            let buffer = buffer.clone();
25016            let task = project.prepare_rename(buffer.clone(), position, cx);
25017            cx.spawn(async move |_, cx| {
25018                Ok(match task.await? {
25019                    PrepareRenameResponse::Success(range) => Some(range),
25020                    PrepareRenameResponse::InvalidPosition => None,
25021                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
25022                        // Fallback on using TreeSitter info to determine identifier range
25023                        buffer.read_with(cx, |buffer, _| {
25024                            let snapshot = buffer.snapshot();
25025                            let (range, kind) = snapshot.surrounding_word(position, None);
25026                            if kind != Some(CharKind::Word) {
25027                                return None;
25028                            }
25029                            Some(
25030                                snapshot.anchor_before(range.start)
25031                                    ..snapshot.anchor_after(range.end),
25032                            )
25033                        })?
25034                    }
25035                })
25036            })
25037        }))
25038    }
25039
25040    fn perform_rename(
25041        &self,
25042        buffer: &Entity<Buffer>,
25043        position: text::Anchor,
25044        new_name: String,
25045        cx: &mut App,
25046    ) -> Option<Task<Result<ProjectTransaction>>> {
25047        Some(self.update(cx, |project, cx| {
25048            project.perform_rename(buffer.clone(), position, new_name, cx)
25049        }))
25050    }
25051}
25052
25053fn consume_contiguous_rows(
25054    contiguous_row_selections: &mut Vec<Selection<Point>>,
25055    selection: &Selection<Point>,
25056    display_map: &DisplaySnapshot,
25057    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
25058) -> (MultiBufferRow, MultiBufferRow) {
25059    contiguous_row_selections.push(selection.clone());
25060    let start_row = starting_row(selection, display_map);
25061    let mut end_row = ending_row(selection, display_map);
25062
25063    while let Some(next_selection) = selections.peek() {
25064        if next_selection.start.row <= end_row.0 {
25065            end_row = ending_row(next_selection, display_map);
25066            contiguous_row_selections.push(selections.next().unwrap().clone());
25067        } else {
25068            break;
25069        }
25070    }
25071    (start_row, end_row)
25072}
25073
25074fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
25075    if selection.start.column > 0 {
25076        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
25077    } else {
25078        MultiBufferRow(selection.start.row)
25079    }
25080}
25081
25082fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
25083    if next_selection.end.column > 0 || next_selection.is_empty() {
25084        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
25085    } else {
25086        MultiBufferRow(next_selection.end.row)
25087    }
25088}
25089
25090impl EditorSnapshot {
25091    pub fn remote_selections_in_range<'a>(
25092        &'a self,
25093        range: &'a Range<Anchor>,
25094        collaboration_hub: &dyn CollaborationHub,
25095        cx: &'a App,
25096    ) -> impl 'a + Iterator<Item = RemoteSelection> {
25097        let participant_names = collaboration_hub.user_names(cx);
25098        let participant_indices = collaboration_hub.user_participant_indices(cx);
25099        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
25100        let collaborators_by_replica_id = collaborators_by_peer_id
25101            .values()
25102            .map(|collaborator| (collaborator.replica_id, collaborator))
25103            .collect::<HashMap<_, _>>();
25104        self.buffer_snapshot()
25105            .selections_in_range(range, false)
25106            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
25107                if replica_id == ReplicaId::AGENT {
25108                    Some(RemoteSelection {
25109                        replica_id,
25110                        selection,
25111                        cursor_shape,
25112                        line_mode,
25113                        collaborator_id: CollaboratorId::Agent,
25114                        user_name: Some("Agent".into()),
25115                        color: cx.theme().players().agent(),
25116                    })
25117                } else {
25118                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
25119                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
25120                    let user_name = participant_names.get(&collaborator.user_id).cloned();
25121                    Some(RemoteSelection {
25122                        replica_id,
25123                        selection,
25124                        cursor_shape,
25125                        line_mode,
25126                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
25127                        user_name,
25128                        color: if let Some(index) = participant_index {
25129                            cx.theme().players().color_for_participant(index.0)
25130                        } else {
25131                            cx.theme().players().absent()
25132                        },
25133                    })
25134                }
25135            })
25136    }
25137
25138    pub fn hunks_for_ranges(
25139        &self,
25140        ranges: impl IntoIterator<Item = Range<Point>>,
25141    ) -> Vec<MultiBufferDiffHunk> {
25142        let mut hunks = Vec::new();
25143        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
25144            HashMap::default();
25145        for query_range in ranges {
25146            let query_rows =
25147                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
25148            for hunk in self.buffer_snapshot().diff_hunks_in_range(
25149                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
25150            ) {
25151                // Include deleted hunks that are adjacent to the query range, because
25152                // otherwise they would be missed.
25153                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
25154                if hunk.status().is_deleted() {
25155                    intersects_range |= hunk.row_range.start == query_rows.end;
25156                    intersects_range |= hunk.row_range.end == query_rows.start;
25157                }
25158                if intersects_range {
25159                    if !processed_buffer_rows
25160                        .entry(hunk.buffer_id)
25161                        .or_default()
25162                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
25163                    {
25164                        continue;
25165                    }
25166                    hunks.push(hunk);
25167                }
25168            }
25169        }
25170
25171        hunks
25172    }
25173
25174    fn display_diff_hunks_for_rows<'a>(
25175        &'a self,
25176        display_rows: Range<DisplayRow>,
25177        folded_buffers: &'a HashSet<BufferId>,
25178    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
25179        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
25180        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
25181
25182        self.buffer_snapshot()
25183            .diff_hunks_in_range(buffer_start..buffer_end)
25184            .filter_map(|hunk| {
25185                if folded_buffers.contains(&hunk.buffer_id) {
25186                    return None;
25187                }
25188
25189                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
25190                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
25191
25192                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
25193                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
25194
25195                let display_hunk = if hunk_display_start.column() != 0 {
25196                    DisplayDiffHunk::Folded {
25197                        display_row: hunk_display_start.row(),
25198                    }
25199                } else {
25200                    let mut end_row = hunk_display_end.row();
25201                    if hunk_display_end.column() > 0 {
25202                        end_row.0 += 1;
25203                    }
25204                    let is_created_file = hunk.is_created_file();
25205
25206                    DisplayDiffHunk::Unfolded {
25207                        status: hunk.status(),
25208                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
25209                            ..hunk.diff_base_byte_range.end.0,
25210                        word_diffs: hunk.word_diffs,
25211                        display_row_range: hunk_display_start.row()..end_row,
25212                        multi_buffer_range: Anchor::range_in_buffer(
25213                            hunk.excerpt_id,
25214                            hunk.buffer_range,
25215                        ),
25216                        is_created_file,
25217                    }
25218                };
25219
25220                Some(display_hunk)
25221            })
25222    }
25223
25224    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
25225        self.display_snapshot
25226            .buffer_snapshot()
25227            .language_at(position)
25228    }
25229
25230    pub fn is_focused(&self) -> bool {
25231        self.is_focused
25232    }
25233
25234    pub fn placeholder_text(&self) -> Option<String> {
25235        self.placeholder_display_snapshot
25236            .as_ref()
25237            .map(|display_map| display_map.text())
25238    }
25239
25240    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
25241        self.scroll_anchor.scroll_position(&self.display_snapshot)
25242    }
25243
25244    pub fn gutter_dimensions(
25245        &self,
25246        font_id: FontId,
25247        font_size: Pixels,
25248        style: &EditorStyle,
25249        window: &mut Window,
25250        cx: &App,
25251    ) -> GutterDimensions {
25252        if self.show_gutter
25253            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
25254            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
25255        {
25256            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
25257                matches!(
25258                    ProjectSettings::get_global(cx).git.git_gutter,
25259                    GitGutterSetting::TrackedFiles
25260                )
25261            });
25262            let gutter_settings = EditorSettings::get_global(cx).gutter;
25263            let show_line_numbers = self
25264                .show_line_numbers
25265                .unwrap_or(gutter_settings.line_numbers);
25266            let line_gutter_width = if show_line_numbers {
25267                // Avoid flicker-like gutter resizes when the line number gains another digit by
25268                // only resizing the gutter on files with > 10**min_line_number_digits lines.
25269                let min_width_for_number_on_gutter =
25270                    ch_advance * gutter_settings.min_line_number_digits as f32;
25271                self.max_line_number_width(style, window)
25272                    .max(min_width_for_number_on_gutter)
25273            } else {
25274                0.0.into()
25275            };
25276
25277            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
25278            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
25279
25280            let git_blame_entries_width =
25281                self.git_blame_gutter_max_author_length
25282                    .map(|max_author_length| {
25283                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
25284                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
25285
25286                        /// The number of characters to dedicate to gaps and margins.
25287                        const SPACING_WIDTH: usize = 4;
25288
25289                        let max_char_count = max_author_length.min(renderer.max_author_length())
25290                            + ::git::SHORT_SHA_LENGTH
25291                            + MAX_RELATIVE_TIMESTAMP.len()
25292                            + SPACING_WIDTH;
25293
25294                        ch_advance * max_char_count
25295                    });
25296
25297            let is_singleton = self.buffer_snapshot().is_singleton();
25298
25299            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
25300            left_padding += if !is_singleton {
25301                ch_width * 4.0
25302            } else if show_runnables || show_breakpoints {
25303                ch_width * 3.0
25304            } else if show_git_gutter && show_line_numbers {
25305                ch_width * 2.0
25306            } else if show_git_gutter || show_line_numbers {
25307                ch_width
25308            } else {
25309                px(0.)
25310            };
25311
25312            let shows_folds = is_singleton && gutter_settings.folds;
25313
25314            let right_padding = if shows_folds && show_line_numbers {
25315                ch_width * 4.0
25316            } else if shows_folds || (!is_singleton && show_line_numbers) {
25317                ch_width * 3.0
25318            } else if show_line_numbers {
25319                ch_width
25320            } else {
25321                px(0.)
25322            };
25323
25324            GutterDimensions {
25325                left_padding,
25326                right_padding,
25327                width: line_gutter_width + left_padding + right_padding,
25328                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
25329                git_blame_entries_width,
25330            }
25331        } else if self.offset_content {
25332            GutterDimensions::default_with_margin(font_id, font_size, cx)
25333        } else {
25334            GutterDimensions::default()
25335        }
25336    }
25337
25338    pub fn render_crease_toggle(
25339        &self,
25340        buffer_row: MultiBufferRow,
25341        row_contains_cursor: bool,
25342        editor: Entity<Editor>,
25343        window: &mut Window,
25344        cx: &mut App,
25345    ) -> Option<AnyElement> {
25346        let folded = self.is_line_folded(buffer_row);
25347        let mut is_foldable = false;
25348
25349        if let Some(crease) = self
25350            .crease_snapshot
25351            .query_row(buffer_row, self.buffer_snapshot())
25352        {
25353            is_foldable = true;
25354            match crease {
25355                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
25356                    if let Some(render_toggle) = render_toggle {
25357                        let toggle_callback =
25358                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
25359                                if folded {
25360                                    editor.update(cx, |editor, cx| {
25361                                        editor.fold_at(buffer_row, window, cx)
25362                                    });
25363                                } else {
25364                                    editor.update(cx, |editor, cx| {
25365                                        editor.unfold_at(buffer_row, window, cx)
25366                                    });
25367                                }
25368                            });
25369                        return Some((render_toggle)(
25370                            buffer_row,
25371                            folded,
25372                            toggle_callback,
25373                            window,
25374                            cx,
25375                        ));
25376                    }
25377                }
25378            }
25379        }
25380
25381        is_foldable |= self.starts_indent(buffer_row);
25382
25383        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
25384            Some(
25385                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
25386                    .toggle_state(folded)
25387                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
25388                        if folded {
25389                            this.unfold_at(buffer_row, window, cx);
25390                        } else {
25391                            this.fold_at(buffer_row, window, cx);
25392                        }
25393                    }))
25394                    .into_any_element(),
25395            )
25396        } else {
25397            None
25398        }
25399    }
25400
25401    pub fn render_crease_trailer(
25402        &self,
25403        buffer_row: MultiBufferRow,
25404        window: &mut Window,
25405        cx: &mut App,
25406    ) -> Option<AnyElement> {
25407        let folded = self.is_line_folded(buffer_row);
25408        if let Crease::Inline { render_trailer, .. } = self
25409            .crease_snapshot
25410            .query_row(buffer_row, self.buffer_snapshot())?
25411        {
25412            let render_trailer = render_trailer.as_ref()?;
25413            Some(render_trailer(buffer_row, folded, window, cx))
25414        } else {
25415            None
25416        }
25417    }
25418
25419    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
25420        let digit_count = self.widest_line_number().ilog10() + 1;
25421        column_pixels(style, digit_count as usize, window)
25422    }
25423
25424    /// Returns the line delta from `base` to `line` in the multibuffer, ignoring wrapped lines.
25425    ///
25426    /// This is positive if `base` is before `line`.
25427    fn relative_line_delta(
25428        &self,
25429        base: DisplayRow,
25430        line: DisplayRow,
25431        consider_wrapped_lines: bool,
25432    ) -> i64 {
25433        let point = DisplayPoint::new(line, 0).to_point(self);
25434        self.relative_line_delta_to_point(base, point, consider_wrapped_lines)
25435    }
25436
25437    /// Returns the line delta from `base` to `point` in the multibuffer.
25438    ///
25439    /// This is positive if `base` is before `point`.
25440    pub fn relative_line_delta_to_point(
25441        &self,
25442        base: DisplayRow,
25443        point: Point,
25444        consider_wrapped_lines: bool,
25445    ) -> i64 {
25446        let base_point = DisplayPoint::new(base, 0).to_point(self);
25447        if consider_wrapped_lines {
25448            let wrap_snapshot = self.wrap_snapshot();
25449            let base_wrap_row = wrap_snapshot.make_wrap_point(base_point, Bias::Left).row();
25450            let wrap_row = wrap_snapshot.make_wrap_point(point, Bias::Left).row();
25451            wrap_row.0 as i64 - base_wrap_row.0 as i64
25452        } else {
25453            point.row as i64 - base_point.row as i64
25454        }
25455    }
25456
25457    /// Returns the unsigned relative line number to display for each row in `rows`.
25458    ///
25459    /// Wrapped rows are excluded from the hashmap if `count_relative_lines` is `false`.
25460    pub fn calculate_relative_line_numbers(
25461        &self,
25462        rows: &Range<DisplayRow>,
25463        relative_to: DisplayRow,
25464        count_wrapped_lines: bool,
25465    ) -> HashMap<DisplayRow, u32> {
25466        let initial_offset = self.relative_line_delta(relative_to, rows.start, count_wrapped_lines);
25467
25468        self.row_infos(rows.start)
25469            .take(rows.len())
25470            .enumerate()
25471            .map(|(i, row_info)| (DisplayRow(rows.start.0 + i as u32), row_info))
25472            .filter(|(_row, row_info)| {
25473                row_info.buffer_row.is_some()
25474                    || (count_wrapped_lines && row_info.wrapped_buffer_row.is_some())
25475            })
25476            .enumerate()
25477            .flat_map(|(i, (row, _row_info))| {
25478                (row != relative_to)
25479                    .then_some((row, (initial_offset + i as i64).unsigned_abs() as u32))
25480            })
25481            .collect()
25482    }
25483}
25484
25485pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
25486    let font_size = style.text.font_size.to_pixels(window.rem_size());
25487    let layout = window.text_system().shape_line(
25488        SharedString::from(" ".repeat(column)),
25489        font_size,
25490        &[TextRun {
25491            len: column,
25492            font: style.text.font(),
25493            color: Hsla::default(),
25494            ..Default::default()
25495        }],
25496        None,
25497    );
25498
25499    layout.width
25500}
25501
25502impl Deref for EditorSnapshot {
25503    type Target = DisplaySnapshot;
25504
25505    fn deref(&self) -> &Self::Target {
25506        &self.display_snapshot
25507    }
25508}
25509
25510#[derive(Clone, Debug, PartialEq, Eq)]
25511pub enum EditorEvent {
25512    InputIgnored {
25513        text: Arc<str>,
25514    },
25515    InputHandled {
25516        utf16_range_to_replace: Option<Range<isize>>,
25517        text: Arc<str>,
25518    },
25519    ExcerptsAdded {
25520        buffer: Entity<Buffer>,
25521        predecessor: ExcerptId,
25522        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
25523    },
25524    ExcerptsRemoved {
25525        ids: Vec<ExcerptId>,
25526        removed_buffer_ids: Vec<BufferId>,
25527    },
25528    BufferFoldToggled {
25529        ids: Vec<ExcerptId>,
25530        folded: bool,
25531    },
25532    ExcerptsEdited {
25533        ids: Vec<ExcerptId>,
25534    },
25535    ExcerptsExpanded {
25536        ids: Vec<ExcerptId>,
25537    },
25538    ExpandExcerptsRequested {
25539        excerpt_ids: Vec<ExcerptId>,
25540        lines: u32,
25541        direction: ExpandExcerptDirection,
25542    },
25543    BufferEdited,
25544    Edited {
25545        transaction_id: clock::Lamport,
25546    },
25547    Reparsed(BufferId),
25548    Focused,
25549    FocusedIn,
25550    Blurred,
25551    DirtyChanged,
25552    Saved,
25553    TitleChanged,
25554    SelectionsChanged {
25555        local: bool,
25556    },
25557    ScrollPositionChanged {
25558        local: bool,
25559        autoscroll: bool,
25560    },
25561    TransactionUndone {
25562        transaction_id: clock::Lamport,
25563    },
25564    TransactionBegun {
25565        transaction_id: clock::Lamport,
25566    },
25567    CursorShapeChanged,
25568    BreadcrumbsChanged,
25569    PushedToNavHistory {
25570        anchor: Anchor,
25571        is_deactivate: bool,
25572    },
25573}
25574
25575impl EventEmitter<EditorEvent> for Editor {}
25576
25577impl Focusable for Editor {
25578    fn focus_handle(&self, _cx: &App) -> FocusHandle {
25579        self.focus_handle.clone()
25580    }
25581}
25582
25583impl Render for Editor {
25584    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25585        EditorElement::new(&cx.entity(), self.create_style(cx))
25586    }
25587}
25588
25589impl EntityInputHandler for Editor {
25590    fn text_for_range(
25591        &mut self,
25592        range_utf16: Range<usize>,
25593        adjusted_range: &mut Option<Range<usize>>,
25594        _: &mut Window,
25595        cx: &mut Context<Self>,
25596    ) -> Option<String> {
25597        let snapshot = self.buffer.read(cx).read(cx);
25598        let start = snapshot.clip_offset_utf16(
25599            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
25600            Bias::Left,
25601        );
25602        let end = snapshot.clip_offset_utf16(
25603            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
25604            Bias::Right,
25605        );
25606        if (start.0.0..end.0.0) != range_utf16 {
25607            adjusted_range.replace(start.0.0..end.0.0);
25608        }
25609        Some(snapshot.text_for_range(start..end).collect())
25610    }
25611
25612    fn selected_text_range(
25613        &mut self,
25614        ignore_disabled_input: bool,
25615        _: &mut Window,
25616        cx: &mut Context<Self>,
25617    ) -> Option<UTF16Selection> {
25618        // Prevent the IME menu from appearing when holding down an alphabetic key
25619        // while input is disabled.
25620        if !ignore_disabled_input && !self.input_enabled {
25621            return None;
25622        }
25623
25624        let selection = self
25625            .selections
25626            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25627        let range = selection.range();
25628
25629        Some(UTF16Selection {
25630            range: range.start.0.0..range.end.0.0,
25631            reversed: selection.reversed,
25632        })
25633    }
25634
25635    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
25636        let snapshot = self.buffer.read(cx).read(cx);
25637        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
25638        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
25639    }
25640
25641    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25642        self.clear_highlights::<InputComposition>(cx);
25643        self.ime_transaction.take();
25644    }
25645
25646    fn replace_text_in_range(
25647        &mut self,
25648        range_utf16: Option<Range<usize>>,
25649        text: &str,
25650        window: &mut Window,
25651        cx: &mut Context<Self>,
25652    ) {
25653        if !self.input_enabled {
25654            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25655            return;
25656        }
25657
25658        self.transact(window, cx, |this, window, cx| {
25659            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
25660                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25661                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25662                Some(this.selection_replacement_ranges(range_utf16, cx))
25663            } else {
25664                this.marked_text_ranges(cx)
25665            };
25666
25667            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
25668                let newest_selection_id = this.selections.newest_anchor().id;
25669                this.selections
25670                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25671                    .iter()
25672                    .zip(ranges_to_replace.iter())
25673                    .find_map(|(selection, range)| {
25674                        if selection.id == newest_selection_id {
25675                            Some(
25676                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25677                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25678                            )
25679                        } else {
25680                            None
25681                        }
25682                    })
25683            });
25684
25685            cx.emit(EditorEvent::InputHandled {
25686                utf16_range_to_replace: range_to_replace,
25687                text: text.into(),
25688            });
25689
25690            if let Some(new_selected_ranges) = new_selected_ranges {
25691                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25692                    selections.select_ranges(new_selected_ranges)
25693                });
25694                this.backspace(&Default::default(), window, cx);
25695            }
25696
25697            this.handle_input(text, window, cx);
25698        });
25699
25700        if let Some(transaction) = self.ime_transaction {
25701            self.buffer.update(cx, |buffer, cx| {
25702                buffer.group_until_transaction(transaction, cx);
25703            });
25704        }
25705
25706        self.unmark_text(window, cx);
25707    }
25708
25709    fn replace_and_mark_text_in_range(
25710        &mut self,
25711        range_utf16: Option<Range<usize>>,
25712        text: &str,
25713        new_selected_range_utf16: Option<Range<usize>>,
25714        window: &mut Window,
25715        cx: &mut Context<Self>,
25716    ) {
25717        if !self.input_enabled {
25718            return;
25719        }
25720
25721        let transaction = self.transact(window, cx, |this, window, cx| {
25722            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
25723                let snapshot = this.buffer.read(cx).read(cx);
25724                if let Some(relative_range_utf16) = range_utf16.as_ref() {
25725                    for marked_range in &mut marked_ranges {
25726                        marked_range.end = marked_range.start + relative_range_utf16.end;
25727                        marked_range.start += relative_range_utf16.start;
25728                        marked_range.start =
25729                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
25730                        marked_range.end =
25731                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
25732                    }
25733                }
25734                Some(marked_ranges)
25735            } else if let Some(range_utf16) = range_utf16 {
25736                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25737                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25738                Some(this.selection_replacement_ranges(range_utf16, cx))
25739            } else {
25740                None
25741            };
25742
25743            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
25744                let newest_selection_id = this.selections.newest_anchor().id;
25745                this.selections
25746                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25747                    .iter()
25748                    .zip(ranges_to_replace.iter())
25749                    .find_map(|(selection, range)| {
25750                        if selection.id == newest_selection_id {
25751                            Some(
25752                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25753                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25754                            )
25755                        } else {
25756                            None
25757                        }
25758                    })
25759            });
25760
25761            cx.emit(EditorEvent::InputHandled {
25762                utf16_range_to_replace: range_to_replace,
25763                text: text.into(),
25764            });
25765
25766            if let Some(ranges) = ranges_to_replace {
25767                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25768                    s.select_ranges(ranges)
25769                });
25770            }
25771
25772            let marked_ranges = {
25773                let snapshot = this.buffer.read(cx).read(cx);
25774                this.selections
25775                    .disjoint_anchors_arc()
25776                    .iter()
25777                    .map(|selection| {
25778                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
25779                    })
25780                    .collect::<Vec<_>>()
25781            };
25782
25783            if text.is_empty() {
25784                this.unmark_text(window, cx);
25785            } else {
25786                this.highlight_text::<InputComposition>(
25787                    marked_ranges.clone(),
25788                    HighlightStyle {
25789                        underline: Some(UnderlineStyle {
25790                            thickness: px(1.),
25791                            color: None,
25792                            wavy: false,
25793                        }),
25794                        ..Default::default()
25795                    },
25796                    cx,
25797                );
25798            }
25799
25800            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
25801            let use_autoclose = this.use_autoclose;
25802            let use_auto_surround = this.use_auto_surround;
25803            this.set_use_autoclose(false);
25804            this.set_use_auto_surround(false);
25805            this.handle_input(text, window, cx);
25806            this.set_use_autoclose(use_autoclose);
25807            this.set_use_auto_surround(use_auto_surround);
25808
25809            if let Some(new_selected_range) = new_selected_range_utf16 {
25810                let snapshot = this.buffer.read(cx).read(cx);
25811                let new_selected_ranges = marked_ranges
25812                    .into_iter()
25813                    .map(|marked_range| {
25814                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
25815                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
25816                            insertion_start.0 + new_selected_range.start,
25817                        ));
25818                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
25819                            insertion_start.0 + new_selected_range.end,
25820                        ));
25821                        snapshot.clip_offset_utf16(new_start, Bias::Left)
25822                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
25823                    })
25824                    .collect::<Vec<_>>();
25825
25826                drop(snapshot);
25827                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25828                    selections.select_ranges(new_selected_ranges)
25829                });
25830            }
25831        });
25832
25833        self.ime_transaction = self.ime_transaction.or(transaction);
25834        if let Some(transaction) = self.ime_transaction {
25835            self.buffer.update(cx, |buffer, cx| {
25836                buffer.group_until_transaction(transaction, cx);
25837            });
25838        }
25839
25840        if self.text_highlights::<InputComposition>(cx).is_none() {
25841            self.ime_transaction.take();
25842        }
25843    }
25844
25845    fn bounds_for_range(
25846        &mut self,
25847        range_utf16: Range<usize>,
25848        element_bounds: gpui::Bounds<Pixels>,
25849        window: &mut Window,
25850        cx: &mut Context<Self>,
25851    ) -> Option<gpui::Bounds<Pixels>> {
25852        let text_layout_details = self.text_layout_details(window);
25853        let CharacterDimensions {
25854            em_width,
25855            em_advance,
25856            line_height,
25857        } = self.character_dimensions(window);
25858
25859        let snapshot = self.snapshot(window, cx);
25860        let scroll_position = snapshot.scroll_position();
25861        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
25862
25863        let start =
25864            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
25865        let x = Pixels::from(
25866            ScrollOffset::from(
25867                snapshot.x_for_display_point(start, &text_layout_details)
25868                    + self.gutter_dimensions.full_width(),
25869            ) - scroll_left,
25870        );
25871        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
25872
25873        Some(Bounds {
25874            origin: element_bounds.origin + point(x, y),
25875            size: size(em_width, line_height),
25876        })
25877    }
25878
25879    fn character_index_for_point(
25880        &mut self,
25881        point: gpui::Point<Pixels>,
25882        _window: &mut Window,
25883        _cx: &mut Context<Self>,
25884    ) -> Option<usize> {
25885        let position_map = self.last_position_map.as_ref()?;
25886        if !position_map.text_hitbox.contains(&point) {
25887            return None;
25888        }
25889        let display_point = position_map.point_for_position(point).previous_valid;
25890        let anchor = position_map
25891            .snapshot
25892            .display_point_to_anchor(display_point, Bias::Left);
25893        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
25894        Some(utf16_offset.0.0)
25895    }
25896
25897    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
25898        self.input_enabled
25899    }
25900}
25901
25902trait SelectionExt {
25903    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
25904    fn spanned_rows(
25905        &self,
25906        include_end_if_at_line_start: bool,
25907        map: &DisplaySnapshot,
25908    ) -> Range<MultiBufferRow>;
25909}
25910
25911impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
25912    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
25913        let start = self
25914            .start
25915            .to_point(map.buffer_snapshot())
25916            .to_display_point(map);
25917        let end = self
25918            .end
25919            .to_point(map.buffer_snapshot())
25920            .to_display_point(map);
25921        if self.reversed {
25922            end..start
25923        } else {
25924            start..end
25925        }
25926    }
25927
25928    fn spanned_rows(
25929        &self,
25930        include_end_if_at_line_start: bool,
25931        map: &DisplaySnapshot,
25932    ) -> Range<MultiBufferRow> {
25933        let start = self.start.to_point(map.buffer_snapshot());
25934        let mut end = self.end.to_point(map.buffer_snapshot());
25935        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
25936            end.row -= 1;
25937        }
25938
25939        let buffer_start = map.prev_line_boundary(start).0;
25940        let buffer_end = map.next_line_boundary(end).0;
25941        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
25942    }
25943}
25944
25945impl<T: InvalidationRegion> InvalidationStack<T> {
25946    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
25947    where
25948        S: Clone + ToOffset,
25949    {
25950        while let Some(region) = self.last() {
25951            let all_selections_inside_invalidation_ranges =
25952                if selections.len() == region.ranges().len() {
25953                    selections
25954                        .iter()
25955                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
25956                        .all(|(selection, invalidation_range)| {
25957                            let head = selection.head().to_offset(buffer);
25958                            invalidation_range.start <= head && invalidation_range.end >= head
25959                        })
25960                } else {
25961                    false
25962                };
25963
25964            if all_selections_inside_invalidation_ranges {
25965                break;
25966            } else {
25967                self.pop();
25968            }
25969        }
25970    }
25971}
25972
25973impl<T> Default for InvalidationStack<T> {
25974    fn default() -> Self {
25975        Self(Default::default())
25976    }
25977}
25978
25979impl<T> Deref for InvalidationStack<T> {
25980    type Target = Vec<T>;
25981
25982    fn deref(&self) -> &Self::Target {
25983        &self.0
25984    }
25985}
25986
25987impl<T> DerefMut for InvalidationStack<T> {
25988    fn deref_mut(&mut self) -> &mut Self::Target {
25989        &mut self.0
25990    }
25991}
25992
25993impl InvalidationRegion for SnippetState {
25994    fn ranges(&self) -> &[Range<Anchor>] {
25995        &self.ranges[self.active_index]
25996    }
25997}
25998
25999fn edit_prediction_edit_text(
26000    current_snapshot: &BufferSnapshot,
26001    edits: &[(Range<Anchor>, impl AsRef<str>)],
26002    edit_preview: &EditPreview,
26003    include_deletions: bool,
26004    cx: &App,
26005) -> HighlightedText {
26006    let edits = edits
26007        .iter()
26008        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
26009        .collect::<Vec<_>>();
26010
26011    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
26012}
26013
26014fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
26015    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
26016    // Just show the raw edit text with basic styling
26017    let mut text = String::new();
26018    let mut highlights = Vec::new();
26019
26020    let insertion_highlight_style = HighlightStyle {
26021        color: Some(cx.theme().colors().text),
26022        ..Default::default()
26023    };
26024
26025    for (_, edit_text) in edits {
26026        let start_offset = text.len();
26027        text.push_str(edit_text);
26028        let end_offset = text.len();
26029
26030        if start_offset < end_offset {
26031            highlights.push((start_offset..end_offset, insertion_highlight_style));
26032        }
26033    }
26034
26035    HighlightedText {
26036        text: text.into(),
26037        highlights,
26038    }
26039}
26040
26041pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
26042    match severity {
26043        lsp::DiagnosticSeverity::ERROR => colors.error,
26044        lsp::DiagnosticSeverity::WARNING => colors.warning,
26045        lsp::DiagnosticSeverity::INFORMATION => colors.info,
26046        lsp::DiagnosticSeverity::HINT => colors.info,
26047        _ => colors.ignored,
26048    }
26049}
26050
26051pub fn styled_runs_for_code_label<'a>(
26052    label: &'a CodeLabel,
26053    syntax_theme: &'a theme::SyntaxTheme,
26054    local_player: &'a theme::PlayerColor,
26055) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
26056    let fade_out = HighlightStyle {
26057        fade_out: Some(0.35),
26058        ..Default::default()
26059    };
26060
26061    let mut prev_end = label.filter_range.end;
26062    label
26063        .runs
26064        .iter()
26065        .enumerate()
26066        .flat_map(move |(ix, (range, highlight_id))| {
26067            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
26068                HighlightStyle {
26069                    color: Some(local_player.cursor),
26070                    ..Default::default()
26071                }
26072            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
26073                HighlightStyle {
26074                    background_color: Some(local_player.selection),
26075                    ..Default::default()
26076                }
26077            } else if let Some(style) = highlight_id.style(syntax_theme) {
26078                style
26079            } else {
26080                return Default::default();
26081            };
26082            let muted_style = style.highlight(fade_out);
26083
26084            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
26085            if range.start >= label.filter_range.end {
26086                if range.start > prev_end {
26087                    runs.push((prev_end..range.start, fade_out));
26088                }
26089                runs.push((range.clone(), muted_style));
26090            } else if range.end <= label.filter_range.end {
26091                runs.push((range.clone(), style));
26092            } else {
26093                runs.push((range.start..label.filter_range.end, style));
26094                runs.push((label.filter_range.end..range.end, muted_style));
26095            }
26096            prev_end = cmp::max(prev_end, range.end);
26097
26098            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
26099                runs.push((prev_end..label.text.len(), fade_out));
26100            }
26101
26102            runs
26103        })
26104}
26105
26106pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
26107    let mut prev_index = 0;
26108    let mut prev_codepoint: Option<char> = None;
26109    text.char_indices()
26110        .chain([(text.len(), '\0')])
26111        .filter_map(move |(index, codepoint)| {
26112            let prev_codepoint = prev_codepoint.replace(codepoint)?;
26113            let is_boundary = index == text.len()
26114                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
26115                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
26116            if is_boundary {
26117                let chunk = &text[prev_index..index];
26118                prev_index = index;
26119                Some(chunk)
26120            } else {
26121                None
26122            }
26123        })
26124}
26125
26126/// Given a string of text immediately before the cursor, iterates over possible
26127/// strings a snippet could match to. More precisely: returns an iterator over
26128/// suffixes of `text` created by splitting at word boundaries (before & after
26129/// every non-word character).
26130///
26131/// Shorter suffixes are returned first.
26132pub(crate) fn snippet_candidate_suffixes(
26133    text: &str,
26134    is_word_char: impl Fn(char) -> bool,
26135) -> impl std::iter::Iterator<Item = &str> {
26136    let mut prev_index = text.len();
26137    let mut prev_codepoint = None;
26138    text.char_indices()
26139        .rev()
26140        .chain([(0, '\0')])
26141        .filter_map(move |(index, codepoint)| {
26142            let prev_index = std::mem::replace(&mut prev_index, index);
26143            let prev_codepoint = prev_codepoint.replace(codepoint)?;
26144            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
26145                None
26146            } else {
26147                let chunk = &text[prev_index..]; // go to end of string
26148                Some(chunk)
26149            }
26150        })
26151}
26152
26153pub trait RangeToAnchorExt: Sized {
26154    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
26155
26156    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
26157        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
26158        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
26159    }
26160}
26161
26162impl<T: ToOffset> RangeToAnchorExt for Range<T> {
26163    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
26164        let start_offset = self.start.to_offset(snapshot);
26165        let end_offset = self.end.to_offset(snapshot);
26166        if start_offset == end_offset {
26167            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
26168        } else {
26169            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
26170        }
26171    }
26172}
26173
26174pub trait RowExt {
26175    fn as_f64(&self) -> f64;
26176
26177    fn next_row(&self) -> Self;
26178
26179    fn previous_row(&self) -> Self;
26180
26181    fn minus(&self, other: Self) -> u32;
26182}
26183
26184impl RowExt for DisplayRow {
26185    fn as_f64(&self) -> f64 {
26186        self.0 as _
26187    }
26188
26189    fn next_row(&self) -> Self {
26190        Self(self.0 + 1)
26191    }
26192
26193    fn previous_row(&self) -> Self {
26194        Self(self.0.saturating_sub(1))
26195    }
26196
26197    fn minus(&self, other: Self) -> u32 {
26198        self.0 - other.0
26199    }
26200}
26201
26202impl RowExt for MultiBufferRow {
26203    fn as_f64(&self) -> f64 {
26204        self.0 as _
26205    }
26206
26207    fn next_row(&self) -> Self {
26208        Self(self.0 + 1)
26209    }
26210
26211    fn previous_row(&self) -> Self {
26212        Self(self.0.saturating_sub(1))
26213    }
26214
26215    fn minus(&self, other: Self) -> u32 {
26216        self.0 - other.0
26217    }
26218}
26219
26220trait RowRangeExt {
26221    type Row;
26222
26223    fn len(&self) -> usize;
26224
26225    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
26226}
26227
26228impl RowRangeExt for Range<MultiBufferRow> {
26229    type Row = MultiBufferRow;
26230
26231    fn len(&self) -> usize {
26232        (self.end.0 - self.start.0) as usize
26233    }
26234
26235    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
26236        (self.start.0..self.end.0).map(MultiBufferRow)
26237    }
26238}
26239
26240impl RowRangeExt for Range<DisplayRow> {
26241    type Row = DisplayRow;
26242
26243    fn len(&self) -> usize {
26244        (self.end.0 - self.start.0) as usize
26245    }
26246
26247    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
26248        (self.start.0..self.end.0).map(DisplayRow)
26249    }
26250}
26251
26252/// If select range has more than one line, we
26253/// just point the cursor to range.start.
26254fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
26255    if range.start.row == range.end.row {
26256        range
26257    } else {
26258        range.start..range.start
26259    }
26260}
26261pub struct KillRing(ClipboardItem);
26262impl Global for KillRing {}
26263
26264const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
26265
26266enum BreakpointPromptEditAction {
26267    Log,
26268    Condition,
26269    HitCondition,
26270}
26271
26272struct BreakpointPromptEditor {
26273    pub(crate) prompt: Entity<Editor>,
26274    editor: WeakEntity<Editor>,
26275    breakpoint_anchor: Anchor,
26276    breakpoint: Breakpoint,
26277    edit_action: BreakpointPromptEditAction,
26278    block_ids: HashSet<CustomBlockId>,
26279    editor_margins: Arc<Mutex<EditorMargins>>,
26280    _subscriptions: Vec<Subscription>,
26281}
26282
26283impl BreakpointPromptEditor {
26284    const MAX_LINES: u8 = 4;
26285
26286    fn new(
26287        editor: WeakEntity<Editor>,
26288        breakpoint_anchor: Anchor,
26289        breakpoint: Breakpoint,
26290        edit_action: BreakpointPromptEditAction,
26291        window: &mut Window,
26292        cx: &mut Context<Self>,
26293    ) -> Self {
26294        let base_text = match edit_action {
26295            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
26296            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
26297            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
26298        }
26299        .map(|msg| msg.to_string())
26300        .unwrap_or_default();
26301
26302        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
26303        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
26304
26305        let prompt = cx.new(|cx| {
26306            let mut prompt = Editor::new(
26307                EditorMode::AutoHeight {
26308                    min_lines: 1,
26309                    max_lines: Some(Self::MAX_LINES as usize),
26310                },
26311                buffer,
26312                None,
26313                window,
26314                cx,
26315            );
26316            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
26317            prompt.set_show_cursor_when_unfocused(false, cx);
26318            prompt.set_placeholder_text(
26319                match edit_action {
26320                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
26321                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
26322                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
26323                },
26324                window,
26325                cx,
26326            );
26327
26328            prompt
26329        });
26330
26331        Self {
26332            prompt,
26333            editor,
26334            breakpoint_anchor,
26335            breakpoint,
26336            edit_action,
26337            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
26338            block_ids: Default::default(),
26339            _subscriptions: vec![],
26340        }
26341    }
26342
26343    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
26344        self.block_ids.extend(block_ids)
26345    }
26346
26347    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
26348        if let Some(editor) = self.editor.upgrade() {
26349            let message = self
26350                .prompt
26351                .read(cx)
26352                .buffer
26353                .read(cx)
26354                .as_singleton()
26355                .expect("A multi buffer in breakpoint prompt isn't possible")
26356                .read(cx)
26357                .as_rope()
26358                .to_string();
26359
26360            editor.update(cx, |editor, cx| {
26361                editor.edit_breakpoint_at_anchor(
26362                    self.breakpoint_anchor,
26363                    self.breakpoint.clone(),
26364                    match self.edit_action {
26365                        BreakpointPromptEditAction::Log => {
26366                            BreakpointEditAction::EditLogMessage(message.into())
26367                        }
26368                        BreakpointPromptEditAction::Condition => {
26369                            BreakpointEditAction::EditCondition(message.into())
26370                        }
26371                        BreakpointPromptEditAction::HitCondition => {
26372                            BreakpointEditAction::EditHitCondition(message.into())
26373                        }
26374                    },
26375                    cx,
26376                );
26377
26378                editor.remove_blocks(self.block_ids.clone(), None, cx);
26379                cx.focus_self(window);
26380            });
26381        }
26382    }
26383
26384    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
26385        self.editor
26386            .update(cx, |editor, cx| {
26387                editor.remove_blocks(self.block_ids.clone(), None, cx);
26388                window.focus(&editor.focus_handle, cx);
26389            })
26390            .log_err();
26391    }
26392
26393    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
26394        let settings = ThemeSettings::get_global(cx);
26395        let text_style = TextStyle {
26396            color: if self.prompt.read(cx).read_only(cx) {
26397                cx.theme().colors().text_disabled
26398            } else {
26399                cx.theme().colors().text
26400            },
26401            font_family: settings.buffer_font.family.clone(),
26402            font_fallbacks: settings.buffer_font.fallbacks.clone(),
26403            font_size: settings.buffer_font_size(cx).into(),
26404            font_weight: settings.buffer_font.weight,
26405            line_height: relative(settings.buffer_line_height.value()),
26406            ..Default::default()
26407        };
26408        EditorElement::new(
26409            &self.prompt,
26410            EditorStyle {
26411                background: cx.theme().colors().editor_background,
26412                local_player: cx.theme().players().local(),
26413                text: text_style,
26414                ..Default::default()
26415            },
26416        )
26417    }
26418}
26419
26420impl Render for BreakpointPromptEditor {
26421    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26422        let editor_margins = *self.editor_margins.lock();
26423        let gutter_dimensions = editor_margins.gutter;
26424        h_flex()
26425            .key_context("Editor")
26426            .bg(cx.theme().colors().editor_background)
26427            .border_y_1()
26428            .border_color(cx.theme().status().info_border)
26429            .size_full()
26430            .py(window.line_height() / 2.5)
26431            .on_action(cx.listener(Self::confirm))
26432            .on_action(cx.listener(Self::cancel))
26433            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
26434            .child(div().flex_1().child(self.render_prompt_editor(cx)))
26435    }
26436}
26437
26438impl Focusable for BreakpointPromptEditor {
26439    fn focus_handle(&self, cx: &App) -> FocusHandle {
26440        self.prompt.focus_handle(cx)
26441    }
26442}
26443
26444fn all_edits_insertions_or_deletions(
26445    edits: &Vec<(Range<Anchor>, Arc<str>)>,
26446    snapshot: &MultiBufferSnapshot,
26447) -> bool {
26448    let mut all_insertions = true;
26449    let mut all_deletions = true;
26450
26451    for (range, new_text) in edits.iter() {
26452        let range_is_empty = range.to_offset(snapshot).is_empty();
26453        let text_is_empty = new_text.is_empty();
26454
26455        if range_is_empty != text_is_empty {
26456            if range_is_empty {
26457                all_deletions = false;
26458            } else {
26459                all_insertions = false;
26460            }
26461        } else {
26462            return false;
26463        }
26464
26465        if !all_insertions && !all_deletions {
26466            return false;
26467        }
26468    }
26469    all_insertions || all_deletions
26470}
26471
26472struct MissingEditPredictionKeybindingTooltip;
26473
26474impl Render for MissingEditPredictionKeybindingTooltip {
26475    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
26476        ui::tooltip_container(cx, |container, cx| {
26477            container
26478                .flex_shrink_0()
26479                .max_w_80()
26480                .min_h(rems_from_px(124.))
26481                .justify_between()
26482                .child(
26483                    v_flex()
26484                        .flex_1()
26485                        .text_ui_sm(cx)
26486                        .child(Label::new("Conflict with Accept Keybinding"))
26487                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
26488                )
26489                .child(
26490                    h_flex()
26491                        .pb_1()
26492                        .gap_1()
26493                        .items_end()
26494                        .w_full()
26495                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
26496                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
26497                        }))
26498                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
26499                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
26500                        })),
26501                )
26502        })
26503    }
26504}
26505
26506#[derive(Debug, Clone, Copy, PartialEq)]
26507pub struct LineHighlight {
26508    pub background: Background,
26509    pub border: Option<gpui::Hsla>,
26510    pub include_gutter: bool,
26511    pub type_id: Option<TypeId>,
26512}
26513
26514struct LineManipulationResult {
26515    pub new_text: String,
26516    pub line_count_before: usize,
26517    pub line_count_after: usize,
26518}
26519
26520fn render_diff_hunk_controls(
26521    row: u32,
26522    status: &DiffHunkStatus,
26523    hunk_range: Range<Anchor>,
26524    is_created_file: bool,
26525    line_height: Pixels,
26526    editor: &Entity<Editor>,
26527    _window: &mut Window,
26528    cx: &mut App,
26529) -> AnyElement {
26530    h_flex()
26531        .h(line_height)
26532        .mr_1()
26533        .gap_1()
26534        .px_0p5()
26535        .pb_1()
26536        .border_x_1()
26537        .border_b_1()
26538        .border_color(cx.theme().colors().border_variant)
26539        .rounded_b_lg()
26540        .bg(cx.theme().colors().editor_background)
26541        .gap_1()
26542        .block_mouse_except_scroll()
26543        .shadow_md()
26544        .child(if status.has_secondary_hunk() {
26545            Button::new(("stage", row as u64), "Stage")
26546                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26547                .tooltip({
26548                    let focus_handle = editor.focus_handle(cx);
26549                    move |_window, cx| {
26550                        Tooltip::for_action_in(
26551                            "Stage Hunk",
26552                            &::git::ToggleStaged,
26553                            &focus_handle,
26554                            cx,
26555                        )
26556                    }
26557                })
26558                .on_click({
26559                    let editor = editor.clone();
26560                    move |_event, _window, cx| {
26561                        editor.update(cx, |editor, cx| {
26562                            editor.stage_or_unstage_diff_hunks(
26563                                true,
26564                                vec![hunk_range.start..hunk_range.start],
26565                                cx,
26566                            );
26567                        });
26568                    }
26569                })
26570        } else {
26571            Button::new(("unstage", row as u64), "Unstage")
26572                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26573                .tooltip({
26574                    let focus_handle = editor.focus_handle(cx);
26575                    move |_window, cx| {
26576                        Tooltip::for_action_in(
26577                            "Unstage Hunk",
26578                            &::git::ToggleStaged,
26579                            &focus_handle,
26580                            cx,
26581                        )
26582                    }
26583                })
26584                .on_click({
26585                    let editor = editor.clone();
26586                    move |_event, _window, cx| {
26587                        editor.update(cx, |editor, cx| {
26588                            editor.stage_or_unstage_diff_hunks(
26589                                false,
26590                                vec![hunk_range.start..hunk_range.start],
26591                                cx,
26592                            );
26593                        });
26594                    }
26595                })
26596        })
26597        .child(
26598            Button::new(("restore", row as u64), "Restore")
26599                .tooltip({
26600                    let focus_handle = editor.focus_handle(cx);
26601                    move |_window, cx| {
26602                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
26603                    }
26604                })
26605                .on_click({
26606                    let editor = editor.clone();
26607                    move |_event, window, cx| {
26608                        editor.update(cx, |editor, cx| {
26609                            let snapshot = editor.snapshot(window, cx);
26610                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
26611                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
26612                        });
26613                    }
26614                })
26615                .disabled(is_created_file),
26616        )
26617        .when(
26618            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
26619            |el| {
26620                el.child(
26621                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
26622                        .shape(IconButtonShape::Square)
26623                        .icon_size(IconSize::Small)
26624                        // .disabled(!has_multiple_hunks)
26625                        .tooltip({
26626                            let focus_handle = editor.focus_handle(cx);
26627                            move |_window, cx| {
26628                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
26629                            }
26630                        })
26631                        .on_click({
26632                            let editor = editor.clone();
26633                            move |_event, window, cx| {
26634                                editor.update(cx, |editor, cx| {
26635                                    let snapshot = editor.snapshot(window, cx);
26636                                    let position =
26637                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
26638                                    editor.go_to_hunk_before_or_after_position(
26639                                        &snapshot,
26640                                        position,
26641                                        Direction::Next,
26642                                        window,
26643                                        cx,
26644                                    );
26645                                    editor.expand_selected_diff_hunks(cx);
26646                                });
26647                            }
26648                        }),
26649                )
26650                .child(
26651                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
26652                        .shape(IconButtonShape::Square)
26653                        .icon_size(IconSize::Small)
26654                        // .disabled(!has_multiple_hunks)
26655                        .tooltip({
26656                            let focus_handle = editor.focus_handle(cx);
26657                            move |_window, cx| {
26658                                Tooltip::for_action_in(
26659                                    "Previous Hunk",
26660                                    &GoToPreviousHunk,
26661                                    &focus_handle,
26662                                    cx,
26663                                )
26664                            }
26665                        })
26666                        .on_click({
26667                            let editor = editor.clone();
26668                            move |_event, window, cx| {
26669                                editor.update(cx, |editor, cx| {
26670                                    let snapshot = editor.snapshot(window, cx);
26671                                    let point =
26672                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
26673                                    editor.go_to_hunk_before_or_after_position(
26674                                        &snapshot,
26675                                        point,
26676                                        Direction::Prev,
26677                                        window,
26678                                        cx,
26679                                    );
26680                                    editor.expand_selected_diff_hunks(cx);
26681                                });
26682                            }
26683                        }),
26684                )
26685            },
26686        )
26687        .into_any_element()
26688}
26689
26690pub fn multibuffer_context_lines(cx: &App) -> u32 {
26691    EditorSettings::try_get(cx)
26692        .map(|settings| settings.excerpt_context_lines)
26693        .unwrap_or(2)
26694        .min(32)
26695}