editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//!
   11//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   12//!
   13//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   14pub mod actions;
   15mod blink_manager;
   16mod clangd_ext;
   17pub mod code_context_menus;
   18pub mod display_map;
   19mod editor_settings;
   20mod element;
   21mod git;
   22mod highlight_matching_bracket;
   23mod hover_links;
   24pub mod hover_popover;
   25mod indent_guides;
   26mod inlays;
   27pub mod items;
   28mod jsx_tag_auto_close;
   29mod linked_editing_ranges;
   30mod lsp_colors;
   31mod lsp_ext;
   32mod mouse_context_menu;
   33pub mod movement;
   34mod persistence;
   35mod proposed_changes_editor;
   36mod rust_analyzer_ext;
   37pub mod scroll;
   38mod selections_collection;
   39pub mod tasks;
   40
   41#[cfg(test)]
   42mod code_completion_tests;
   43#[cfg(test)]
   44mod edit_prediction_tests;
   45#[cfg(test)]
   46mod editor_tests;
   47mod signature_help;
   48#[cfg(any(test, feature = "test-support"))]
   49pub mod test;
   50
   51pub(crate) use actions::*;
   52pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   53pub use edit_prediction::Direction;
   54pub use editor_settings::{
   55    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   56    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   57};
   58pub use element::{
   59    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   60};
   61pub use git::blame::BlameRenderer;
   62pub use hover_popover::hover_markdown_style;
   63pub use inlays::Inlay;
   64pub use items::MAX_TAB_TITLE_LEN;
   65pub use lsp::CompletionContext;
   66pub use lsp_ext::lsp_tasks;
   67pub use multi_buffer::{
   68    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   69    RowInfo, ToOffset, ToPoint,
   70};
   71pub use proposed_changes_editor::{
   72    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   73};
   74pub use text::Bias;
   75
   76use ::git::{
   77    Restore,
   78    blame::{BlameEntry, ParsedCommitMessage},
   79};
   80use aho_corasick::AhoCorasick;
   81use anyhow::{Context as _, Result, anyhow};
   82use blink_manager::BlinkManager;
   83use buffer_diff::DiffHunkStatus;
   84use client::{Collaborator, ParticipantIndex, parse_zed_link};
   85use clock::ReplicaId;
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   91use convert_case::{Case, Casing};
   92use dap::TelemetrySpawnLocation;
   93use display_map::*;
   94use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   95use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   96use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   97use futures::{
   98    FutureExt, StreamExt as _,
   99    future::{self, Shared, join},
  100    stream::FuturesUnordered,
  101};
  102use fuzzy::{StringMatch, StringMatchCandidate};
  103use git::blame::{GitBlame, GlobalBlameRenderer};
  104use gpui::{
  105    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  106    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  107    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  108    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  109    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  110    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  111    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  112    div, point, prelude::*, pulsating_between, px, relative, size,
  113};
  114use highlight_matching_bracket::refresh_matching_bracket_highlights;
  115use hover_links::{HoverLink, HoveredLinkState, find_file};
  116use hover_popover::{HoverState, hide_hover};
  117use indent_guides::ActiveIndentGuidesState;
  118use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  119use itertools::{Either, Itertools};
  120use language::{
  121    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  122    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  123    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  124    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  125    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  126    language_settings::{
  127        self, LspInsertMode, RewrapBehavior, WordsCompletionMode, all_language_settings,
  128        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    ToOffsetUtf16,
  144};
  145use parking_lot::Mutex;
  146use persistence::DB;
  147use project::{
  148    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  149    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  150    InvalidationStrategy, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem,
  151    ProjectPath, ProjectTransaction, TaskSourceKind,
  152    debugger::{
  153        breakpoint_store::{
  154            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  155            BreakpointStore, BreakpointStoreEvent,
  156        },
  157        session::{Session, SessionEvent},
  158    },
  159    git_store::{GitStoreEvent, RepositoryEvent},
  160    lsp_store::{
  161        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  162        OpenLspBufferHandle,
  163    },
  164    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  165};
  166use rand::seq::SliceRandom;
  167use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  168use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  169use selections_collection::{
  170    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  171};
  172use serde::{Deserialize, Serialize};
  173use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  174use smallvec::{SmallVec, smallvec};
  175use snippet::Snippet;
  176use std::{
  177    any::{Any, TypeId},
  178    borrow::Cow,
  179    cell::{OnceCell, RefCell},
  180    cmp::{self, Ordering, Reverse},
  181    iter::{self, Peekable},
  182    mem,
  183    num::NonZeroU32,
  184    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  185    path::{Path, PathBuf},
  186    rc::Rc,
  187    sync::Arc,
  188    time::{Duration, Instant},
  189};
  190use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  191use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  192use theme::{
  193    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  194    observe_buffer_font_size_adjustment,
  195};
  196use ui::{
  197    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  198    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  199};
  200use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  201use workspace::{
  202    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  203    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  204    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  205    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  206    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  207    searchable::SearchEvent,
  208};
  209
  210use crate::{
  211    code_context_menus::CompletionsMenuSource,
  212    editor_settings::MultiCursorModifier,
  213    hover_links::{find_url, find_url_from_range},
  214    inlays::{
  215        InlineValueCache,
  216        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  217    },
  218    scroll::{ScrollOffset, ScrollPixelOffset},
  219    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  220};
  221
  222pub const FILE_HEADER_HEIGHT: u32 = 2;
  223pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  224const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  225const MAX_LINE_LEN: usize = 1024;
  226const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  227const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  228pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  229#[doc(hidden)]
  230pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  231pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  232
  233pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  234pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  235pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  236pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  237
  238pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  239pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  240pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  241
  242pub type RenderDiffHunkControlsFn = Arc<
  243    dyn Fn(
  244        u32,
  245        &DiffHunkStatus,
  246        Range<Anchor>,
  247        bool,
  248        Pixels,
  249        &Entity<Editor>,
  250        &mut Window,
  251        &mut App,
  252    ) -> AnyElement,
  253>;
  254
  255enum ReportEditorEvent {
  256    Saved { auto_saved: bool },
  257    EditorOpened,
  258    Closed,
  259}
  260
  261impl ReportEditorEvent {
  262    pub fn event_type(&self) -> &'static str {
  263        match self {
  264            Self::Saved { .. } => "Editor Saved",
  265            Self::EditorOpened => "Editor Opened",
  266            Self::Closed => "Editor Closed",
  267        }
  268    }
  269}
  270
  271pub enum ActiveDebugLine {}
  272pub enum DebugStackFrameLine {}
  273enum DocumentHighlightRead {}
  274enum DocumentHighlightWrite {}
  275enum InputComposition {}
  276pub enum PendingInput {}
  277enum SelectedTextHighlight {}
  278
  279pub enum ConflictsOuter {}
  280pub enum ConflictsOurs {}
  281pub enum ConflictsTheirs {}
  282pub enum ConflictsOursMarker {}
  283pub enum ConflictsTheirsMarker {}
  284
  285#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  286pub enum Navigated {
  287    Yes,
  288    No,
  289}
  290
  291impl Navigated {
  292    pub fn from_bool(yes: bool) -> Navigated {
  293        if yes { Navigated::Yes } else { Navigated::No }
  294    }
  295}
  296
  297#[derive(Debug, Clone, PartialEq, Eq)]
  298enum DisplayDiffHunk {
  299    Folded {
  300        display_row: DisplayRow,
  301    },
  302    Unfolded {
  303        is_created_file: bool,
  304        diff_base_byte_range: Range<usize>,
  305        display_row_range: Range<DisplayRow>,
  306        multi_buffer_range: Range<Anchor>,
  307        status: DiffHunkStatus,
  308    },
  309}
  310
  311pub enum HideMouseCursorOrigin {
  312    TypingAction,
  313    MovementAction,
  314}
  315
  316pub fn init_settings(cx: &mut App) {
  317    EditorSettings::register(cx);
  318}
  319
  320pub fn init(cx: &mut App) {
  321    init_settings(cx);
  322
  323    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  324
  325    workspace::register_project_item::<Editor>(cx);
  326    workspace::FollowableViewRegistry::register::<Editor>(cx);
  327    workspace::register_serializable_item::<Editor>(cx);
  328
  329    cx.observe_new(
  330        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  331            workspace.register_action(Editor::new_file);
  332            workspace.register_action(Editor::new_file_split);
  333            workspace.register_action(Editor::new_file_vertical);
  334            workspace.register_action(Editor::new_file_horizontal);
  335            workspace.register_action(Editor::cancel_language_server_work);
  336            workspace.register_action(Editor::toggle_focus);
  337        },
  338    )
  339    .detach();
  340
  341    cx.on_action(move |_: &workspace::NewFile, cx| {
  342        let app_state = workspace::AppState::global(cx);
  343        if let Some(app_state) = app_state.upgrade() {
  344            workspace::open_new(
  345                Default::default(),
  346                app_state,
  347                cx,
  348                |workspace, window, cx| {
  349                    Editor::new_file(workspace, &Default::default(), window, cx)
  350                },
  351            )
  352            .detach();
  353        }
  354    });
  355    cx.on_action(move |_: &workspace::NewWindow, cx| {
  356        let app_state = workspace::AppState::global(cx);
  357        if let Some(app_state) = app_state.upgrade() {
  358            workspace::open_new(
  359                Default::default(),
  360                app_state,
  361                cx,
  362                |workspace, window, cx| {
  363                    cx.activate(true);
  364                    Editor::new_file(workspace, &Default::default(), window, cx)
  365                },
  366            )
  367            .detach();
  368        }
  369    });
  370}
  371
  372pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  373    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  374}
  375
  376pub trait DiagnosticRenderer {
  377    fn render_group(
  378        &self,
  379        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  380        buffer_id: BufferId,
  381        snapshot: EditorSnapshot,
  382        editor: WeakEntity<Editor>,
  383        cx: &mut App,
  384    ) -> Vec<BlockProperties<Anchor>>;
  385
  386    fn render_hover(
  387        &self,
  388        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  389        range: Range<Point>,
  390        buffer_id: BufferId,
  391        cx: &mut App,
  392    ) -> Option<Entity<markdown::Markdown>>;
  393
  394    fn open_link(
  395        &self,
  396        editor: &mut Editor,
  397        link: SharedString,
  398        window: &mut Window,
  399        cx: &mut Context<Editor>,
  400    );
  401}
  402
  403pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  404
  405impl GlobalDiagnosticRenderer {
  406    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  407        cx.try_global::<Self>().map(|g| g.0.clone())
  408    }
  409}
  410
  411impl gpui::Global for GlobalDiagnosticRenderer {}
  412pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  413    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  414}
  415
  416pub struct SearchWithinRange;
  417
  418trait InvalidationRegion {
  419    fn ranges(&self) -> &[Range<Anchor>];
  420}
  421
  422#[derive(Clone, Debug, PartialEq)]
  423pub enum SelectPhase {
  424    Begin {
  425        position: DisplayPoint,
  426        add: bool,
  427        click_count: usize,
  428    },
  429    BeginColumnar {
  430        position: DisplayPoint,
  431        reset: bool,
  432        mode: ColumnarMode,
  433        goal_column: u32,
  434    },
  435    Extend {
  436        position: DisplayPoint,
  437        click_count: usize,
  438    },
  439    Update {
  440        position: DisplayPoint,
  441        goal_column: u32,
  442        scroll_delta: gpui::Point<f32>,
  443    },
  444    End,
  445}
  446
  447#[derive(Clone, Debug, PartialEq)]
  448pub enum ColumnarMode {
  449    FromMouse,
  450    FromSelection,
  451}
  452
  453#[derive(Clone, Debug)]
  454pub enum SelectMode {
  455    Character,
  456    Word(Range<Anchor>),
  457    Line(Range<Anchor>),
  458    All,
  459}
  460
  461#[derive(Clone, PartialEq, Eq, Debug)]
  462pub enum EditorMode {
  463    SingleLine,
  464    AutoHeight {
  465        min_lines: usize,
  466        max_lines: Option<usize>,
  467    },
  468    Full {
  469        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  470        scale_ui_elements_with_buffer_font_size: bool,
  471        /// When set to `true`, the editor will render a background for the active line.
  472        show_active_line_background: bool,
  473        /// When set to `true`, the editor's height will be determined by its content.
  474        sized_by_content: bool,
  475    },
  476    Minimap {
  477        parent: WeakEntity<Editor>,
  478    },
  479}
  480
  481impl EditorMode {
  482    pub fn full() -> Self {
  483        Self::Full {
  484            scale_ui_elements_with_buffer_font_size: true,
  485            show_active_line_background: true,
  486            sized_by_content: false,
  487        }
  488    }
  489
  490    #[inline]
  491    pub fn is_full(&self) -> bool {
  492        matches!(self, Self::Full { .. })
  493    }
  494
  495    #[inline]
  496    pub fn is_single_line(&self) -> bool {
  497        matches!(self, Self::SingleLine { .. })
  498    }
  499
  500    #[inline]
  501    fn is_minimap(&self) -> bool {
  502        matches!(self, Self::Minimap { .. })
  503    }
  504}
  505
  506#[derive(Copy, Clone, Debug)]
  507pub enum SoftWrap {
  508    /// Prefer not to wrap at all.
  509    ///
  510    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  511    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  512    GitDiff,
  513    /// Prefer a single line generally, unless an overly long line is encountered.
  514    None,
  515    /// Soft wrap lines that exceed the editor width.
  516    EditorWidth,
  517    /// Soft wrap lines at the preferred line length.
  518    Column(u32),
  519    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  520    Bounded(u32),
  521}
  522
  523#[derive(Clone)]
  524pub struct EditorStyle {
  525    pub background: Hsla,
  526    pub border: Hsla,
  527    pub local_player: PlayerColor,
  528    pub text: TextStyle,
  529    pub scrollbar_width: Pixels,
  530    pub syntax: Arc<SyntaxTheme>,
  531    pub status: StatusColors,
  532    pub inlay_hints_style: HighlightStyle,
  533    pub edit_prediction_styles: EditPredictionStyles,
  534    pub unnecessary_code_fade: f32,
  535    pub show_underlines: bool,
  536}
  537
  538impl Default for EditorStyle {
  539    fn default() -> Self {
  540        Self {
  541            background: Hsla::default(),
  542            border: Hsla::default(),
  543            local_player: PlayerColor::default(),
  544            text: TextStyle::default(),
  545            scrollbar_width: Pixels::default(),
  546            syntax: Default::default(),
  547            // HACK: Status colors don't have a real default.
  548            // We should look into removing the status colors from the editor
  549            // style and retrieve them directly from the theme.
  550            status: StatusColors::dark(),
  551            inlay_hints_style: HighlightStyle::default(),
  552            edit_prediction_styles: EditPredictionStyles {
  553                insertion: HighlightStyle::default(),
  554                whitespace: HighlightStyle::default(),
  555            },
  556            unnecessary_code_fade: Default::default(),
  557            show_underlines: true,
  558        }
  559    }
  560}
  561
  562pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  563    let show_background = language_settings::language_settings(None, None, cx)
  564        .inlay_hints
  565        .show_background;
  566
  567    let mut style = cx.theme().syntax().get("hint");
  568
  569    if style.color.is_none() {
  570        style.color = Some(cx.theme().status().hint);
  571    }
  572
  573    if !show_background {
  574        style.background_color = None;
  575        return style;
  576    }
  577
  578    if style.background_color.is_none() {
  579        style.background_color = Some(cx.theme().status().hint_background);
  580    }
  581
  582    style
  583}
  584
  585pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  586    EditPredictionStyles {
  587        insertion: HighlightStyle {
  588            color: Some(cx.theme().status().predictive),
  589            ..HighlightStyle::default()
  590        },
  591        whitespace: HighlightStyle {
  592            background_color: Some(cx.theme().status().created_background),
  593            ..HighlightStyle::default()
  594        },
  595    }
  596}
  597
  598type CompletionId = usize;
  599
  600pub(crate) enum EditDisplayMode {
  601    TabAccept,
  602    DiffPopover,
  603    Inline,
  604}
  605
  606enum EditPrediction {
  607    Edit {
  608        edits: Vec<(Range<Anchor>, String)>,
  609        edit_preview: Option<EditPreview>,
  610        display_mode: EditDisplayMode,
  611        snapshot: BufferSnapshot,
  612    },
  613    /// Move to a specific location in the active editor
  614    MoveWithin {
  615        target: Anchor,
  616        snapshot: BufferSnapshot,
  617    },
  618    /// Move to a specific location in a different editor (not the active one)
  619    MoveOutside {
  620        target: language::Anchor,
  621        snapshot: BufferSnapshot,
  622    },
  623}
  624
  625struct EditPredictionState {
  626    inlay_ids: Vec<InlayId>,
  627    completion: EditPrediction,
  628    completion_id: Option<SharedString>,
  629    invalidation_range: Option<Range<Anchor>>,
  630}
  631
  632enum EditPredictionSettings {
  633    Disabled,
  634    Enabled {
  635        show_in_menu: bool,
  636        preview_requires_modifier: bool,
  637    },
  638}
  639
  640enum EditPredictionHighlight {}
  641
  642#[derive(Debug, Clone)]
  643struct InlineDiagnostic {
  644    message: SharedString,
  645    group_id: usize,
  646    is_primary: bool,
  647    start: Point,
  648    severity: lsp::DiagnosticSeverity,
  649}
  650
  651pub enum MenuEditPredictionsPolicy {
  652    Never,
  653    ByProvider,
  654}
  655
  656pub enum EditPredictionPreview {
  657    /// Modifier is not pressed
  658    Inactive { released_too_fast: bool },
  659    /// Modifier pressed
  660    Active {
  661        since: Instant,
  662        previous_scroll_position: Option<ScrollAnchor>,
  663    },
  664}
  665
  666impl EditPredictionPreview {
  667    pub fn released_too_fast(&self) -> bool {
  668        match self {
  669            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  670            EditPredictionPreview::Active { .. } => false,
  671        }
  672    }
  673
  674    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  675        if let EditPredictionPreview::Active {
  676            previous_scroll_position,
  677            ..
  678        } = self
  679        {
  680            *previous_scroll_position = scroll_position;
  681        }
  682    }
  683}
  684
  685pub struct ContextMenuOptions {
  686    pub min_entries_visible: usize,
  687    pub max_entries_visible: usize,
  688    pub placement: Option<ContextMenuPlacement>,
  689}
  690
  691#[derive(Debug, Clone, PartialEq, Eq)]
  692pub enum ContextMenuPlacement {
  693    Above,
  694    Below,
  695}
  696
  697#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  698struct EditorActionId(usize);
  699
  700impl EditorActionId {
  701    pub fn post_inc(&mut self) -> Self {
  702        let answer = self.0;
  703
  704        *self = Self(answer + 1);
  705
  706        Self(answer)
  707    }
  708}
  709
  710// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  711// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  712
  713type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  714type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  715
  716#[derive(Default)]
  717struct ScrollbarMarkerState {
  718    scrollbar_size: Size<Pixels>,
  719    dirty: bool,
  720    markers: Arc<[PaintQuad]>,
  721    pending_refresh: Option<Task<Result<()>>>,
  722}
  723
  724impl ScrollbarMarkerState {
  725    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  726        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  727    }
  728}
  729
  730#[derive(Clone, Copy, PartialEq, Eq)]
  731pub enum MinimapVisibility {
  732    Disabled,
  733    Enabled {
  734        /// The configuration currently present in the users settings.
  735        setting_configuration: bool,
  736        /// Whether to override the currently set visibility from the users setting.
  737        toggle_override: bool,
  738    },
  739}
  740
  741impl MinimapVisibility {
  742    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  743        if mode.is_full() {
  744            Self::Enabled {
  745                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  746                toggle_override: false,
  747            }
  748        } else {
  749            Self::Disabled
  750        }
  751    }
  752
  753    fn hidden(&self) -> Self {
  754        match *self {
  755            Self::Enabled {
  756                setting_configuration,
  757                ..
  758            } => Self::Enabled {
  759                setting_configuration,
  760                toggle_override: setting_configuration,
  761            },
  762            Self::Disabled => Self::Disabled,
  763        }
  764    }
  765
  766    fn disabled(&self) -> bool {
  767        matches!(*self, Self::Disabled)
  768    }
  769
  770    fn settings_visibility(&self) -> bool {
  771        match *self {
  772            Self::Enabled {
  773                setting_configuration,
  774                ..
  775            } => setting_configuration,
  776            _ => false,
  777        }
  778    }
  779
  780    fn visible(&self) -> bool {
  781        match *self {
  782            Self::Enabled {
  783                setting_configuration,
  784                toggle_override,
  785            } => setting_configuration ^ toggle_override,
  786            _ => false,
  787        }
  788    }
  789
  790    fn toggle_visibility(&self) -> Self {
  791        match *self {
  792            Self::Enabled {
  793                toggle_override,
  794                setting_configuration,
  795            } => Self::Enabled {
  796                setting_configuration,
  797                toggle_override: !toggle_override,
  798            },
  799            Self::Disabled => Self::Disabled,
  800        }
  801    }
  802}
  803
  804#[derive(Clone, Debug)]
  805struct RunnableTasks {
  806    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  807    offset: multi_buffer::Anchor,
  808    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  809    column: u32,
  810    // Values of all named captures, including those starting with '_'
  811    extra_variables: HashMap<String, String>,
  812    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  813    context_range: Range<BufferOffset>,
  814}
  815
  816impl RunnableTasks {
  817    fn resolve<'a>(
  818        &'a self,
  819        cx: &'a task::TaskContext,
  820    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  821        self.templates.iter().filter_map(|(kind, template)| {
  822            template
  823                .resolve_task(&kind.to_id_base(), cx)
  824                .map(|task| (kind.clone(), task))
  825        })
  826    }
  827}
  828
  829#[derive(Clone)]
  830pub struct ResolvedTasks {
  831    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  832    position: Anchor,
  833}
  834
  835#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  836struct BufferOffset(usize);
  837
  838/// Addons allow storing per-editor state in other crates (e.g. Vim)
  839pub trait Addon: 'static {
  840    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  841
  842    fn render_buffer_header_controls(
  843        &self,
  844        _: &ExcerptInfo,
  845        _: &Window,
  846        _: &App,
  847    ) -> Option<AnyElement> {
  848        None
  849    }
  850
  851    fn to_any(&self) -> &dyn std::any::Any;
  852
  853    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  854        None
  855    }
  856}
  857
  858struct ChangeLocation {
  859    current: Option<Vec<Anchor>>,
  860    original: Vec<Anchor>,
  861}
  862impl ChangeLocation {
  863    fn locations(&self) -> &[Anchor] {
  864        self.current.as_ref().unwrap_or(&self.original)
  865    }
  866}
  867
  868/// A set of caret positions, registered when the editor was edited.
  869pub struct ChangeList {
  870    changes: Vec<ChangeLocation>,
  871    /// Currently "selected" change.
  872    position: Option<usize>,
  873}
  874
  875impl ChangeList {
  876    pub fn new() -> Self {
  877        Self {
  878            changes: Vec::new(),
  879            position: None,
  880        }
  881    }
  882
  883    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  884    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  885    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  886        if self.changes.is_empty() {
  887            return None;
  888        }
  889
  890        let prev = self.position.unwrap_or(self.changes.len());
  891        let next = if direction == Direction::Prev {
  892            prev.saturating_sub(count)
  893        } else {
  894            (prev + count).min(self.changes.len() - 1)
  895        };
  896        self.position = Some(next);
  897        self.changes.get(next).map(|change| change.locations())
  898    }
  899
  900    /// Adds a new change to the list, resetting the change list position.
  901    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  902        self.position.take();
  903        if let Some(last) = self.changes.last_mut()
  904            && group
  905        {
  906            last.current = Some(new_positions)
  907        } else {
  908            self.changes.push(ChangeLocation {
  909                original: new_positions,
  910                current: None,
  911            });
  912        }
  913    }
  914
  915    pub fn last(&self) -> Option<&[Anchor]> {
  916        self.changes.last().map(|change| change.locations())
  917    }
  918
  919    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  920        self.changes.last().map(|change| change.original.as_slice())
  921    }
  922
  923    pub fn invert_last_group(&mut self) {
  924        if let Some(last) = self.changes.last_mut()
  925            && let Some(current) = last.current.as_mut()
  926        {
  927            mem::swap(&mut last.original, current);
  928        }
  929    }
  930}
  931
  932#[derive(Clone)]
  933struct InlineBlamePopoverState {
  934    scroll_handle: ScrollHandle,
  935    commit_message: Option<ParsedCommitMessage>,
  936    markdown: Entity<Markdown>,
  937}
  938
  939struct InlineBlamePopover {
  940    position: gpui::Point<Pixels>,
  941    hide_task: Option<Task<()>>,
  942    popover_bounds: Option<Bounds<Pixels>>,
  943    popover_state: InlineBlamePopoverState,
  944    keyboard_grace: bool,
  945}
  946
  947enum SelectionDragState {
  948    /// State when no drag related activity is detected.
  949    None,
  950    /// State when the mouse is down on a selection that is about to be dragged.
  951    ReadyToDrag {
  952        selection: Selection<Anchor>,
  953        click_position: gpui::Point<Pixels>,
  954        mouse_down_time: Instant,
  955    },
  956    /// State when the mouse is dragging the selection in the editor.
  957    Dragging {
  958        selection: Selection<Anchor>,
  959        drop_cursor: Selection<Anchor>,
  960        hide_drop_cursor: bool,
  961    },
  962}
  963
  964enum ColumnarSelectionState {
  965    FromMouse {
  966        selection_tail: Anchor,
  967        display_point: Option<DisplayPoint>,
  968    },
  969    FromSelection {
  970        selection_tail: Anchor,
  971    },
  972}
  973
  974/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  975/// a breakpoint on them.
  976#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  977struct PhantomBreakpointIndicator {
  978    display_row: DisplayRow,
  979    /// There's a small debounce between hovering over the line and showing the indicator.
  980    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  981    is_active: bool,
  982    collides_with_existing_breakpoint: bool,
  983}
  984
  985/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  986///
  987/// See the [module level documentation](self) for more information.
  988pub struct Editor {
  989    focus_handle: FocusHandle,
  990    last_focused_descendant: Option<WeakFocusHandle>,
  991    /// The text buffer being edited
  992    buffer: Entity<MultiBuffer>,
  993    /// Map of how text in the buffer should be displayed.
  994    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  995    pub display_map: Entity<DisplayMap>,
  996    placeholder_display_map: Option<Entity<DisplayMap>>,
  997    pub selections: SelectionsCollection,
  998    pub scroll_manager: ScrollManager,
  999    /// When inline assist editors are linked, they all render cursors because
 1000    /// typing enters text into each of them, even the ones that aren't focused.
 1001    pub(crate) show_cursor_when_unfocused: bool,
 1002    columnar_selection_state: Option<ColumnarSelectionState>,
 1003    add_selections_state: Option<AddSelectionsState>,
 1004    select_next_state: Option<SelectNextState>,
 1005    select_prev_state: Option<SelectNextState>,
 1006    selection_history: SelectionHistory,
 1007    defer_selection_effects: bool,
 1008    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1009    autoclose_regions: Vec<AutocloseRegion>,
 1010    snippet_stack: InvalidationStack<SnippetState>,
 1011    select_syntax_node_history: SelectSyntaxNodeHistory,
 1012    ime_transaction: Option<TransactionId>,
 1013    pub diagnostics_max_severity: DiagnosticSeverity,
 1014    active_diagnostics: ActiveDiagnostic,
 1015    show_inline_diagnostics: bool,
 1016    inline_diagnostics_update: Task<()>,
 1017    inline_diagnostics_enabled: bool,
 1018    diagnostics_enabled: bool,
 1019    word_completions_enabled: bool,
 1020    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1021    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1022    hard_wrap: Option<usize>,
 1023    project: Option<Entity<Project>>,
 1024    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1025    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1026    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1027    blink_manager: Entity<BlinkManager>,
 1028    show_cursor_names: bool,
 1029    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1030    pub show_local_selections: bool,
 1031    mode: EditorMode,
 1032    show_breadcrumbs: bool,
 1033    show_gutter: bool,
 1034    show_scrollbars: ScrollbarAxes,
 1035    minimap_visibility: MinimapVisibility,
 1036    offset_content: bool,
 1037    disable_expand_excerpt_buttons: bool,
 1038    show_line_numbers: Option<bool>,
 1039    use_relative_line_numbers: Option<bool>,
 1040    show_git_diff_gutter: Option<bool>,
 1041    show_code_actions: Option<bool>,
 1042    show_runnables: Option<bool>,
 1043    show_breakpoints: Option<bool>,
 1044    show_wrap_guides: Option<bool>,
 1045    show_indent_guides: Option<bool>,
 1046    highlight_order: usize,
 1047    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1048    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1049    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1050    scrollbar_marker_state: ScrollbarMarkerState,
 1051    active_indent_guides_state: ActiveIndentGuidesState,
 1052    nav_history: Option<ItemNavHistory>,
 1053    context_menu: RefCell<Option<CodeContextMenu>>,
 1054    context_menu_options: Option<ContextMenuOptions>,
 1055    mouse_context_menu: Option<MouseContextMenu>,
 1056    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1057    inline_blame_popover: Option<InlineBlamePopover>,
 1058    inline_blame_popover_show_task: Option<Task<()>>,
 1059    signature_help_state: SignatureHelpState,
 1060    auto_signature_help: Option<bool>,
 1061    find_all_references_task_sources: Vec<Anchor>,
 1062    next_completion_id: CompletionId,
 1063    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1064    code_actions_task: Option<Task<Result<()>>>,
 1065    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1066    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1067    document_highlights_task: Option<Task<()>>,
 1068    linked_editing_range_task: Option<Task<Option<()>>>,
 1069    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1070    pending_rename: Option<RenameState>,
 1071    searchable: bool,
 1072    cursor_shape: CursorShape,
 1073    current_line_highlight: Option<CurrentLineHighlight>,
 1074    collapse_matches: bool,
 1075    autoindent_mode: Option<AutoindentMode>,
 1076    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1077    input_enabled: bool,
 1078    use_modal_editing: bool,
 1079    read_only: bool,
 1080    leader_id: Option<CollaboratorId>,
 1081    remote_id: Option<ViewId>,
 1082    pub hover_state: HoverState,
 1083    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1084    gutter_hovered: bool,
 1085    hovered_link_state: Option<HoveredLinkState>,
 1086    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1087    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1088    active_edit_prediction: Option<EditPredictionState>,
 1089    /// Used to prevent flickering as the user types while the menu is open
 1090    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1091    edit_prediction_settings: EditPredictionSettings,
 1092    edit_predictions_hidden_for_vim_mode: bool,
 1093    show_edit_predictions_override: Option<bool>,
 1094    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1095    edit_prediction_preview: EditPredictionPreview,
 1096    edit_prediction_indent_conflict: bool,
 1097    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1098    next_inlay_id: usize,
 1099    next_color_inlay_id: usize,
 1100    _subscriptions: Vec<Subscription>,
 1101    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1102    gutter_dimensions: GutterDimensions,
 1103    style: Option<EditorStyle>,
 1104    text_style_refinement: Option<TextStyleRefinement>,
 1105    next_editor_action_id: EditorActionId,
 1106    editor_actions: Rc<
 1107        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1108    >,
 1109    use_autoclose: bool,
 1110    use_auto_surround: bool,
 1111    auto_replace_emoji_shortcode: bool,
 1112    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1113    show_git_blame_gutter: bool,
 1114    show_git_blame_inline: bool,
 1115    show_git_blame_inline_delay_task: Option<Task<()>>,
 1116    git_blame_inline_enabled: bool,
 1117    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1118    serialize_dirty_buffers: bool,
 1119    show_selection_menu: Option<bool>,
 1120    blame: Option<Entity<GitBlame>>,
 1121    blame_subscription: Option<Subscription>,
 1122    custom_context_menu: Option<
 1123        Box<
 1124            dyn 'static
 1125                + Fn(
 1126                    &mut Self,
 1127                    DisplayPoint,
 1128                    &mut Window,
 1129                    &mut Context<Self>,
 1130                ) -> Option<Entity<ui::ContextMenu>>,
 1131        >,
 1132    >,
 1133    last_bounds: Option<Bounds<Pixels>>,
 1134    last_position_map: Option<Rc<PositionMap>>,
 1135    expect_bounds_change: Option<Bounds<Pixels>>,
 1136    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1137    tasks_update_task: Option<Task<()>>,
 1138    breakpoint_store: Option<Entity<BreakpointStore>>,
 1139    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1140    hovered_diff_hunk_row: Option<DisplayRow>,
 1141    pull_diagnostics_task: Task<()>,
 1142    in_project_search: bool,
 1143    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1144    breadcrumb_header: Option<String>,
 1145    focused_block: Option<FocusedBlock>,
 1146    next_scroll_position: NextScrollCursorCenterTopBottom,
 1147    addons: HashMap<TypeId, Box<dyn Addon>>,
 1148    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1149    load_diff_task: Option<Shared<Task<()>>>,
 1150    /// Whether we are temporarily displaying a diff other than git's
 1151    temporary_diff_override: bool,
 1152    selection_mark_mode: bool,
 1153    toggle_fold_multiple_buffers: Task<()>,
 1154    _scroll_cursor_center_top_bottom_task: Task<()>,
 1155    serialize_selections: Task<()>,
 1156    serialize_folds: Task<()>,
 1157    mouse_cursor_hidden: bool,
 1158    minimap: Option<Entity<Self>>,
 1159    hide_mouse_mode: HideMouseMode,
 1160    pub change_list: ChangeList,
 1161    inline_value_cache: InlineValueCache,
 1162    selection_drag_state: SelectionDragState,
 1163    colors: Option<LspColorData>,
 1164    post_scroll_update: Task<()>,
 1165    refresh_colors_task: Task<()>,
 1166    inlay_hints: Option<LspInlayHintData>,
 1167    folding_newlines: Task<()>,
 1168    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1169}
 1170
 1171fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1172    if debounce_ms > 0 {
 1173        Some(Duration::from_millis(debounce_ms))
 1174    } else {
 1175        None
 1176    }
 1177}
 1178
 1179#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1180enum NextScrollCursorCenterTopBottom {
 1181    #[default]
 1182    Center,
 1183    Top,
 1184    Bottom,
 1185}
 1186
 1187impl NextScrollCursorCenterTopBottom {
 1188    fn next(&self) -> Self {
 1189        match self {
 1190            Self::Center => Self::Top,
 1191            Self::Top => Self::Bottom,
 1192            Self::Bottom => Self::Center,
 1193        }
 1194    }
 1195}
 1196
 1197#[derive(Clone)]
 1198pub struct EditorSnapshot {
 1199    pub mode: EditorMode,
 1200    show_gutter: bool,
 1201    show_line_numbers: Option<bool>,
 1202    show_git_diff_gutter: Option<bool>,
 1203    show_code_actions: Option<bool>,
 1204    show_runnables: Option<bool>,
 1205    show_breakpoints: Option<bool>,
 1206    git_blame_gutter_max_author_length: Option<usize>,
 1207    pub display_snapshot: DisplaySnapshot,
 1208    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1209    is_focused: bool,
 1210    scroll_anchor: ScrollAnchor,
 1211    ongoing_scroll: OngoingScroll,
 1212    current_line_highlight: CurrentLineHighlight,
 1213    gutter_hovered: bool,
 1214}
 1215
 1216#[derive(Default, Debug, Clone, Copy)]
 1217pub struct GutterDimensions {
 1218    pub left_padding: Pixels,
 1219    pub right_padding: Pixels,
 1220    pub width: Pixels,
 1221    pub margin: Pixels,
 1222    pub git_blame_entries_width: Option<Pixels>,
 1223}
 1224
 1225impl GutterDimensions {
 1226    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1227        Self {
 1228            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1229            ..Default::default()
 1230        }
 1231    }
 1232
 1233    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1234        -cx.text_system().descent(font_id, font_size)
 1235    }
 1236    /// The full width of the space taken up by the gutter.
 1237    pub fn full_width(&self) -> Pixels {
 1238        self.margin + self.width
 1239    }
 1240
 1241    /// The width of the space reserved for the fold indicators,
 1242    /// use alongside 'justify_end' and `gutter_width` to
 1243    /// right align content with the line numbers
 1244    pub fn fold_area_width(&self) -> Pixels {
 1245        self.margin + self.right_padding
 1246    }
 1247}
 1248
 1249struct CharacterDimensions {
 1250    em_width: Pixels,
 1251    em_advance: Pixels,
 1252    line_height: Pixels,
 1253}
 1254
 1255#[derive(Debug)]
 1256pub struct RemoteSelection {
 1257    pub replica_id: ReplicaId,
 1258    pub selection: Selection<Anchor>,
 1259    pub cursor_shape: CursorShape,
 1260    pub collaborator_id: CollaboratorId,
 1261    pub line_mode: bool,
 1262    pub user_name: Option<SharedString>,
 1263    pub color: PlayerColor,
 1264}
 1265
 1266#[derive(Clone, Debug)]
 1267struct SelectionHistoryEntry {
 1268    selections: Arc<[Selection<Anchor>]>,
 1269    select_next_state: Option<SelectNextState>,
 1270    select_prev_state: Option<SelectNextState>,
 1271    add_selections_state: Option<AddSelectionsState>,
 1272}
 1273
 1274#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1275enum SelectionHistoryMode {
 1276    Normal,
 1277    Undoing,
 1278    Redoing,
 1279    Skipping,
 1280}
 1281
 1282#[derive(Clone, PartialEq, Eq, Hash)]
 1283struct HoveredCursor {
 1284    replica_id: ReplicaId,
 1285    selection_id: usize,
 1286}
 1287
 1288impl Default for SelectionHistoryMode {
 1289    fn default() -> Self {
 1290        Self::Normal
 1291    }
 1292}
 1293
 1294#[derive(Debug)]
 1295/// SelectionEffects controls the side-effects of updating the selection.
 1296///
 1297/// The default behaviour does "what you mostly want":
 1298/// - it pushes to the nav history if the cursor moved by >10 lines
 1299/// - it re-triggers completion requests
 1300/// - it scrolls to fit
 1301///
 1302/// You might want to modify these behaviours. For example when doing a "jump"
 1303/// like go to definition, we always want to add to nav history; but when scrolling
 1304/// in vim mode we never do.
 1305///
 1306/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1307/// move.
 1308#[derive(Clone)]
 1309pub struct SelectionEffects {
 1310    nav_history: Option<bool>,
 1311    completions: bool,
 1312    scroll: Option<Autoscroll>,
 1313}
 1314
 1315impl Default for SelectionEffects {
 1316    fn default() -> Self {
 1317        Self {
 1318            nav_history: None,
 1319            completions: true,
 1320            scroll: Some(Autoscroll::fit()),
 1321        }
 1322    }
 1323}
 1324impl SelectionEffects {
 1325    pub fn scroll(scroll: Autoscroll) -> Self {
 1326        Self {
 1327            scroll: Some(scroll),
 1328            ..Default::default()
 1329        }
 1330    }
 1331
 1332    pub fn no_scroll() -> Self {
 1333        Self {
 1334            scroll: None,
 1335            ..Default::default()
 1336        }
 1337    }
 1338
 1339    pub fn completions(self, completions: bool) -> Self {
 1340        Self {
 1341            completions,
 1342            ..self
 1343        }
 1344    }
 1345
 1346    pub fn nav_history(self, nav_history: bool) -> Self {
 1347        Self {
 1348            nav_history: Some(nav_history),
 1349            ..self
 1350        }
 1351    }
 1352}
 1353
 1354struct DeferredSelectionEffectsState {
 1355    changed: bool,
 1356    effects: SelectionEffects,
 1357    old_cursor_position: Anchor,
 1358    history_entry: SelectionHistoryEntry,
 1359}
 1360
 1361#[derive(Default)]
 1362struct SelectionHistory {
 1363    #[allow(clippy::type_complexity)]
 1364    selections_by_transaction:
 1365        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1366    mode: SelectionHistoryMode,
 1367    undo_stack: VecDeque<SelectionHistoryEntry>,
 1368    redo_stack: VecDeque<SelectionHistoryEntry>,
 1369}
 1370
 1371impl SelectionHistory {
 1372    #[track_caller]
 1373    fn insert_transaction(
 1374        &mut self,
 1375        transaction_id: TransactionId,
 1376        selections: Arc<[Selection<Anchor>]>,
 1377    ) {
 1378        if selections.is_empty() {
 1379            log::error!(
 1380                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1381                std::panic::Location::caller()
 1382            );
 1383            return;
 1384        }
 1385        self.selections_by_transaction
 1386            .insert(transaction_id, (selections, None));
 1387    }
 1388
 1389    #[allow(clippy::type_complexity)]
 1390    fn transaction(
 1391        &self,
 1392        transaction_id: TransactionId,
 1393    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1394        self.selections_by_transaction.get(&transaction_id)
 1395    }
 1396
 1397    #[allow(clippy::type_complexity)]
 1398    fn transaction_mut(
 1399        &mut self,
 1400        transaction_id: TransactionId,
 1401    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1402        self.selections_by_transaction.get_mut(&transaction_id)
 1403    }
 1404
 1405    fn push(&mut self, entry: SelectionHistoryEntry) {
 1406        if !entry.selections.is_empty() {
 1407            match self.mode {
 1408                SelectionHistoryMode::Normal => {
 1409                    self.push_undo(entry);
 1410                    self.redo_stack.clear();
 1411                }
 1412                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1413                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1414                SelectionHistoryMode::Skipping => {}
 1415            }
 1416        }
 1417    }
 1418
 1419    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1420        if self
 1421            .undo_stack
 1422            .back()
 1423            .is_none_or(|e| e.selections != entry.selections)
 1424        {
 1425            self.undo_stack.push_back(entry);
 1426            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1427                self.undo_stack.pop_front();
 1428            }
 1429        }
 1430    }
 1431
 1432    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1433        if self
 1434            .redo_stack
 1435            .back()
 1436            .is_none_or(|e| e.selections != entry.selections)
 1437        {
 1438            self.redo_stack.push_back(entry);
 1439            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1440                self.redo_stack.pop_front();
 1441            }
 1442        }
 1443    }
 1444}
 1445
 1446#[derive(Clone, Copy)]
 1447pub struct RowHighlightOptions {
 1448    pub autoscroll: bool,
 1449    pub include_gutter: bool,
 1450}
 1451
 1452impl Default for RowHighlightOptions {
 1453    fn default() -> Self {
 1454        Self {
 1455            autoscroll: Default::default(),
 1456            include_gutter: true,
 1457        }
 1458    }
 1459}
 1460
 1461struct RowHighlight {
 1462    index: usize,
 1463    range: Range<Anchor>,
 1464    color: Hsla,
 1465    options: RowHighlightOptions,
 1466    type_id: TypeId,
 1467}
 1468
 1469#[derive(Clone, Debug)]
 1470struct AddSelectionsState {
 1471    groups: Vec<AddSelectionsGroup>,
 1472}
 1473
 1474#[derive(Clone, Debug)]
 1475struct AddSelectionsGroup {
 1476    above: bool,
 1477    stack: Vec<usize>,
 1478}
 1479
 1480#[derive(Clone)]
 1481struct SelectNextState {
 1482    query: AhoCorasick,
 1483    wordwise: bool,
 1484    done: bool,
 1485}
 1486
 1487impl std::fmt::Debug for SelectNextState {
 1488    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1489        f.debug_struct(std::any::type_name::<Self>())
 1490            .field("wordwise", &self.wordwise)
 1491            .field("done", &self.done)
 1492            .finish()
 1493    }
 1494}
 1495
 1496#[derive(Debug)]
 1497struct AutocloseRegion {
 1498    selection_id: usize,
 1499    range: Range<Anchor>,
 1500    pair: BracketPair,
 1501}
 1502
 1503#[derive(Debug)]
 1504struct SnippetState {
 1505    ranges: Vec<Vec<Range<Anchor>>>,
 1506    active_index: usize,
 1507    choices: Vec<Option<Vec<String>>>,
 1508}
 1509
 1510#[doc(hidden)]
 1511pub struct RenameState {
 1512    pub range: Range<Anchor>,
 1513    pub old_name: Arc<str>,
 1514    pub editor: Entity<Editor>,
 1515    block_id: CustomBlockId,
 1516}
 1517
 1518struct InvalidationStack<T>(Vec<T>);
 1519
 1520struct RegisteredEditPredictionProvider {
 1521    provider: Arc<dyn EditPredictionProviderHandle>,
 1522    _subscription: Subscription,
 1523}
 1524
 1525#[derive(Debug, PartialEq, Eq)]
 1526pub struct ActiveDiagnosticGroup {
 1527    pub active_range: Range<Anchor>,
 1528    pub active_message: String,
 1529    pub group_id: usize,
 1530    pub blocks: HashSet<CustomBlockId>,
 1531}
 1532
 1533#[derive(Debug, PartialEq, Eq)]
 1534
 1535pub(crate) enum ActiveDiagnostic {
 1536    None,
 1537    All,
 1538    Group(ActiveDiagnosticGroup),
 1539}
 1540
 1541#[derive(Serialize, Deserialize, Clone, Debug)]
 1542pub struct ClipboardSelection {
 1543    /// The number of bytes in this selection.
 1544    pub len: usize,
 1545    /// Whether this was a full-line selection.
 1546    pub is_entire_line: bool,
 1547    /// The indentation of the first line when this content was originally copied.
 1548    pub first_line_indent: u32,
 1549}
 1550
 1551// selections, scroll behavior, was newest selection reversed
 1552type SelectSyntaxNodeHistoryState = (
 1553    Box<[Selection<usize>]>,
 1554    SelectSyntaxNodeScrollBehavior,
 1555    bool,
 1556);
 1557
 1558#[derive(Default)]
 1559struct SelectSyntaxNodeHistory {
 1560    stack: Vec<SelectSyntaxNodeHistoryState>,
 1561    // disable temporarily to allow changing selections without losing the stack
 1562    pub disable_clearing: bool,
 1563}
 1564
 1565impl SelectSyntaxNodeHistory {
 1566    pub fn try_clear(&mut self) {
 1567        if !self.disable_clearing {
 1568            self.stack.clear();
 1569        }
 1570    }
 1571
 1572    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1573        self.stack.push(selection);
 1574    }
 1575
 1576    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1577        self.stack.pop()
 1578    }
 1579}
 1580
 1581enum SelectSyntaxNodeScrollBehavior {
 1582    CursorTop,
 1583    FitSelection,
 1584    CursorBottom,
 1585}
 1586
 1587#[derive(Debug)]
 1588pub(crate) struct NavigationData {
 1589    cursor_anchor: Anchor,
 1590    cursor_position: Point,
 1591    scroll_anchor: ScrollAnchor,
 1592    scroll_top_row: u32,
 1593}
 1594
 1595#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1596pub enum GotoDefinitionKind {
 1597    Symbol,
 1598    Declaration,
 1599    Type,
 1600    Implementation,
 1601}
 1602
 1603pub enum FormatTarget {
 1604    Buffers(HashSet<Entity<Buffer>>),
 1605    Ranges(Vec<Range<MultiBufferPoint>>),
 1606}
 1607
 1608pub(crate) struct FocusedBlock {
 1609    id: BlockId,
 1610    focus_handle: WeakFocusHandle,
 1611}
 1612
 1613#[derive(Clone)]
 1614enum JumpData {
 1615    MultiBufferRow {
 1616        row: MultiBufferRow,
 1617        line_offset_from_top: u32,
 1618    },
 1619    MultiBufferPoint {
 1620        excerpt_id: ExcerptId,
 1621        position: Point,
 1622        anchor: text::Anchor,
 1623        line_offset_from_top: u32,
 1624    },
 1625}
 1626
 1627pub enum MultibufferSelectionMode {
 1628    First,
 1629    All,
 1630}
 1631
 1632#[derive(Clone, Copy, Debug, Default)]
 1633pub struct RewrapOptions {
 1634    pub override_language_settings: bool,
 1635    pub preserve_existing_whitespace: bool,
 1636}
 1637
 1638impl Editor {
 1639    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1640        let buffer = cx.new(|cx| Buffer::local("", cx));
 1641        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1642        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1643    }
 1644
 1645    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1646        let buffer = cx.new(|cx| Buffer::local("", cx));
 1647        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1648        Self::new(EditorMode::full(), buffer, None, window, cx)
 1649    }
 1650
 1651    pub fn auto_height(
 1652        min_lines: usize,
 1653        max_lines: usize,
 1654        window: &mut Window,
 1655        cx: &mut Context<Self>,
 1656    ) -> Self {
 1657        let buffer = cx.new(|cx| Buffer::local("", cx));
 1658        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1659        Self::new(
 1660            EditorMode::AutoHeight {
 1661                min_lines,
 1662                max_lines: Some(max_lines),
 1663            },
 1664            buffer,
 1665            None,
 1666            window,
 1667            cx,
 1668        )
 1669    }
 1670
 1671    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1672    /// The editor grows as tall as needed to fit its content.
 1673    pub fn auto_height_unbounded(
 1674        min_lines: usize,
 1675        window: &mut Window,
 1676        cx: &mut Context<Self>,
 1677    ) -> Self {
 1678        let buffer = cx.new(|cx| Buffer::local("", cx));
 1679        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1680        Self::new(
 1681            EditorMode::AutoHeight {
 1682                min_lines,
 1683                max_lines: None,
 1684            },
 1685            buffer,
 1686            None,
 1687            window,
 1688            cx,
 1689        )
 1690    }
 1691
 1692    pub fn for_buffer(
 1693        buffer: Entity<Buffer>,
 1694        project: Option<Entity<Project>>,
 1695        window: &mut Window,
 1696        cx: &mut Context<Self>,
 1697    ) -> Self {
 1698        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1699        Self::new(EditorMode::full(), buffer, project, window, cx)
 1700    }
 1701
 1702    pub fn for_multibuffer(
 1703        buffer: Entity<MultiBuffer>,
 1704        project: Option<Entity<Project>>,
 1705        window: &mut Window,
 1706        cx: &mut Context<Self>,
 1707    ) -> Self {
 1708        Self::new(EditorMode::full(), buffer, project, window, cx)
 1709    }
 1710
 1711    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1712        let mut clone = Self::new(
 1713            self.mode.clone(),
 1714            self.buffer.clone(),
 1715            self.project.clone(),
 1716            window,
 1717            cx,
 1718        );
 1719        self.display_map.update(cx, |display_map, cx| {
 1720            let snapshot = display_map.snapshot(cx);
 1721            clone.display_map.update(cx, |display_map, cx| {
 1722                display_map.set_state(&snapshot, cx);
 1723            });
 1724        });
 1725        clone.folds_did_change(cx);
 1726        clone.selections.clone_state(&self.selections);
 1727        clone.scroll_manager.clone_state(&self.scroll_manager);
 1728        clone.searchable = self.searchable;
 1729        clone.read_only = self.read_only;
 1730        clone
 1731    }
 1732
 1733    pub fn new(
 1734        mode: EditorMode,
 1735        buffer: Entity<MultiBuffer>,
 1736        project: Option<Entity<Project>>,
 1737        window: &mut Window,
 1738        cx: &mut Context<Self>,
 1739    ) -> Self {
 1740        Editor::new_internal(mode, buffer, project, None, window, cx)
 1741    }
 1742
 1743    fn new_internal(
 1744        mode: EditorMode,
 1745        multi_buffer: Entity<MultiBuffer>,
 1746        project: Option<Entity<Project>>,
 1747        display_map: Option<Entity<DisplayMap>>,
 1748        window: &mut Window,
 1749        cx: &mut Context<Self>,
 1750    ) -> Self {
 1751        debug_assert!(
 1752            display_map.is_none() || mode.is_minimap(),
 1753            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1754        );
 1755
 1756        let full_mode = mode.is_full();
 1757        let is_minimap = mode.is_minimap();
 1758        let diagnostics_max_severity = if full_mode {
 1759            EditorSettings::get_global(cx)
 1760                .diagnostics_max_severity
 1761                .unwrap_or(DiagnosticSeverity::Hint)
 1762        } else {
 1763            DiagnosticSeverity::Off
 1764        };
 1765        let style = window.text_style();
 1766        let font_size = style.font_size.to_pixels(window.rem_size());
 1767        let editor = cx.entity().downgrade();
 1768        let fold_placeholder = FoldPlaceholder {
 1769            constrain_width: false,
 1770            render: Arc::new(move |fold_id, fold_range, cx| {
 1771                let editor = editor.clone();
 1772                div()
 1773                    .id(fold_id)
 1774                    .bg(cx.theme().colors().ghost_element_background)
 1775                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1776                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1777                    .rounded_xs()
 1778                    .size_full()
 1779                    .cursor_pointer()
 1780                    .child("")
 1781                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1782                    .on_click(move |_, _window, cx| {
 1783                        editor
 1784                            .update(cx, |editor, cx| {
 1785                                editor.unfold_ranges(
 1786                                    &[fold_range.start..fold_range.end],
 1787                                    true,
 1788                                    false,
 1789                                    cx,
 1790                                );
 1791                                cx.stop_propagation();
 1792                            })
 1793                            .ok();
 1794                    })
 1795                    .into_any()
 1796            }),
 1797            merge_adjacent: true,
 1798            ..FoldPlaceholder::default()
 1799        };
 1800        let display_map = display_map.unwrap_or_else(|| {
 1801            cx.new(|cx| {
 1802                DisplayMap::new(
 1803                    multi_buffer.clone(),
 1804                    style.font(),
 1805                    font_size,
 1806                    None,
 1807                    FILE_HEADER_HEIGHT,
 1808                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1809                    fold_placeholder,
 1810                    diagnostics_max_severity,
 1811                    cx,
 1812                )
 1813            })
 1814        });
 1815
 1816        let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
 1817
 1818        let blink_manager = cx.new(|cx| {
 1819            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1820            if is_minimap {
 1821                blink_manager.disable(cx);
 1822            }
 1823            blink_manager
 1824        });
 1825
 1826        let soft_wrap_mode_override =
 1827            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1828
 1829        let mut project_subscriptions = Vec::new();
 1830        if full_mode && let Some(project) = project.as_ref() {
 1831            project_subscriptions.push(cx.subscribe_in(
 1832                project,
 1833                window,
 1834                |editor, _, event, window, cx| match event {
 1835                    project::Event::RefreshCodeLens => {
 1836                        // we always query lens with actions, without storing them, always refreshing them
 1837                    }
 1838                    project::Event::RefreshInlayHints(server_id) => {
 1839                        editor.refresh_inlay_hints(
 1840                            InlayHintRefreshReason::RefreshRequested(*server_id),
 1841                            cx,
 1842                        );
 1843                    }
 1844                    project::Event::LanguageServerRemoved(..) => {
 1845                        if editor.tasks_update_task.is_none() {
 1846                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1847                        }
 1848                        editor.registered_buffers.clear();
 1849                        editor.register_visible_buffers(cx);
 1850                    }
 1851                    project::Event::LanguageServerAdded(..) => {
 1852                        if editor.tasks_update_task.is_none() {
 1853                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1854                        }
 1855                    }
 1856                    project::Event::SnippetEdit(id, snippet_edits) => {
 1857                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1858                            let focus_handle = editor.focus_handle(cx);
 1859                            if focus_handle.is_focused(window) {
 1860                                let snapshot = buffer.read(cx).snapshot();
 1861                                for (range, snippet) in snippet_edits {
 1862                                    let editor_range =
 1863                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1864                                    editor
 1865                                        .insert_snippet(
 1866                                            &[editor_range],
 1867                                            snippet.clone(),
 1868                                            window,
 1869                                            cx,
 1870                                        )
 1871                                        .ok();
 1872                                }
 1873                            }
 1874                        }
 1875                    }
 1876                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1877                        let buffer_id = *buffer_id;
 1878                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1879                            editor.register_buffer(buffer_id, cx);
 1880                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1881                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1882                            refresh_linked_ranges(editor, window, cx);
 1883                            editor.refresh_code_actions(window, cx);
 1884                            editor.refresh_document_highlights(cx);
 1885                        }
 1886                    }
 1887
 1888                    project::Event::EntryRenamed(transaction) => {
 1889                        let Some(workspace) = editor.workspace() else {
 1890                            return;
 1891                        };
 1892                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1893                        else {
 1894                            return;
 1895                        };
 1896                        if active_editor.entity_id() == cx.entity_id() {
 1897                            let edited_buffers_already_open = {
 1898                                let other_editors: Vec<Entity<Editor>> = workspace
 1899                                    .read(cx)
 1900                                    .panes()
 1901                                    .iter()
 1902                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1903                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1904                                    .collect();
 1905
 1906                                transaction.0.keys().all(|buffer| {
 1907                                    other_editors.iter().any(|editor| {
 1908                                        let multi_buffer = editor.read(cx).buffer();
 1909                                        multi_buffer.read(cx).is_singleton()
 1910                                            && multi_buffer.read(cx).as_singleton().map_or(
 1911                                                false,
 1912                                                |singleton| {
 1913                                                    singleton.entity_id() == buffer.entity_id()
 1914                                                },
 1915                                            )
 1916                                    })
 1917                                })
 1918                            };
 1919
 1920                            if !edited_buffers_already_open {
 1921                                let workspace = workspace.downgrade();
 1922                                let transaction = transaction.clone();
 1923                                cx.defer_in(window, move |_, window, cx| {
 1924                                    cx.spawn_in(window, async move |editor, cx| {
 1925                                        Self::open_project_transaction(
 1926                                            &editor,
 1927                                            workspace,
 1928                                            transaction,
 1929                                            "Rename".to_string(),
 1930                                            cx,
 1931                                        )
 1932                                        .await
 1933                                        .ok()
 1934                                    })
 1935                                    .detach();
 1936                                });
 1937                            }
 1938                        }
 1939                    }
 1940
 1941                    _ => {}
 1942                },
 1943            ));
 1944            if let Some(task_inventory) = project
 1945                .read(cx)
 1946                .task_store()
 1947                .read(cx)
 1948                .task_inventory()
 1949                .cloned()
 1950            {
 1951                project_subscriptions.push(cx.observe_in(
 1952                    &task_inventory,
 1953                    window,
 1954                    |editor, _, window, cx| {
 1955                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1956                    },
 1957                ));
 1958            };
 1959
 1960            project_subscriptions.push(cx.subscribe_in(
 1961                &project.read(cx).breakpoint_store(),
 1962                window,
 1963                |editor, _, event, window, cx| match event {
 1964                    BreakpointStoreEvent::ClearDebugLines => {
 1965                        editor.clear_row_highlights::<ActiveDebugLine>();
 1966                        editor.refresh_inline_values(cx);
 1967                    }
 1968                    BreakpointStoreEvent::SetDebugLine => {
 1969                        if editor.go_to_active_debug_line(window, cx) {
 1970                            cx.stop_propagation();
 1971                        }
 1972
 1973                        editor.refresh_inline_values(cx);
 1974                    }
 1975                    _ => {}
 1976                },
 1977            ));
 1978            let git_store = project.read(cx).git_store().clone();
 1979            let project = project.clone();
 1980            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1981                if let GitStoreEvent::RepositoryUpdated(
 1982                    _,
 1983                    RepositoryEvent::Updated {
 1984                        new_instance: true, ..
 1985                    },
 1986                    _,
 1987                ) = event
 1988                {
 1989                    this.load_diff_task = Some(
 1990                        update_uncommitted_diff_for_buffer(
 1991                            cx.entity(),
 1992                            &project,
 1993                            this.buffer.read(cx).all_buffers(),
 1994                            this.buffer.clone(),
 1995                            cx,
 1996                        )
 1997                        .shared(),
 1998                    );
 1999                }
 2000            }));
 2001        }
 2002
 2003        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2004
 2005        let inlay_hint_settings =
 2006            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2007        let focus_handle = cx.focus_handle();
 2008        if !is_minimap {
 2009            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2010                .detach();
 2011            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2012                .detach();
 2013            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2014                .detach();
 2015            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2016                .detach();
 2017            cx.observe_pending_input(window, Self::observe_pending_input)
 2018                .detach();
 2019        }
 2020
 2021        let show_indent_guides =
 2022            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2023                Some(false)
 2024            } else {
 2025                None
 2026            };
 2027
 2028        let breakpoint_store = match (&mode, project.as_ref()) {
 2029            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2030            _ => None,
 2031        };
 2032
 2033        let mut code_action_providers = Vec::new();
 2034        let mut load_uncommitted_diff = None;
 2035        if let Some(project) = project.clone() {
 2036            load_uncommitted_diff = Some(
 2037                update_uncommitted_diff_for_buffer(
 2038                    cx.entity(),
 2039                    &project,
 2040                    multi_buffer.read(cx).all_buffers(),
 2041                    multi_buffer.clone(),
 2042                    cx,
 2043                )
 2044                .shared(),
 2045            );
 2046            code_action_providers.push(Rc::new(project) as Rc<_>);
 2047        }
 2048
 2049        let mut editor = Self {
 2050            focus_handle,
 2051            show_cursor_when_unfocused: false,
 2052            last_focused_descendant: None,
 2053            buffer: multi_buffer.clone(),
 2054            display_map: display_map.clone(),
 2055            placeholder_display_map: None,
 2056            selections,
 2057            scroll_manager: ScrollManager::new(cx),
 2058            columnar_selection_state: None,
 2059            add_selections_state: None,
 2060            select_next_state: None,
 2061            select_prev_state: None,
 2062            selection_history: SelectionHistory::default(),
 2063            defer_selection_effects: false,
 2064            deferred_selection_effects_state: None,
 2065            autoclose_regions: Vec::new(),
 2066            snippet_stack: InvalidationStack::default(),
 2067            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2068            ime_transaction: None,
 2069            active_diagnostics: ActiveDiagnostic::None,
 2070            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2071            inline_diagnostics_update: Task::ready(()),
 2072            inline_diagnostics: Vec::new(),
 2073            soft_wrap_mode_override,
 2074            diagnostics_max_severity,
 2075            hard_wrap: None,
 2076            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2077            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2078            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2079            project,
 2080            blink_manager: blink_manager.clone(),
 2081            show_local_selections: true,
 2082            show_scrollbars: ScrollbarAxes {
 2083                horizontal: full_mode,
 2084                vertical: full_mode,
 2085            },
 2086            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2087            offset_content: !matches!(mode, EditorMode::SingleLine),
 2088            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2089            show_gutter: full_mode,
 2090            show_line_numbers: (!full_mode).then_some(false),
 2091            use_relative_line_numbers: None,
 2092            disable_expand_excerpt_buttons: !full_mode,
 2093            show_git_diff_gutter: None,
 2094            show_code_actions: None,
 2095            show_runnables: None,
 2096            show_breakpoints: None,
 2097            show_wrap_guides: None,
 2098            show_indent_guides,
 2099            highlight_order: 0,
 2100            highlighted_rows: HashMap::default(),
 2101            background_highlights: HashMap::default(),
 2102            gutter_highlights: HashMap::default(),
 2103            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2104            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2105            nav_history: None,
 2106            context_menu: RefCell::new(None),
 2107            context_menu_options: None,
 2108            mouse_context_menu: None,
 2109            completion_tasks: Vec::new(),
 2110            inline_blame_popover: None,
 2111            inline_blame_popover_show_task: None,
 2112            signature_help_state: SignatureHelpState::default(),
 2113            auto_signature_help: None,
 2114            find_all_references_task_sources: Vec::new(),
 2115            next_completion_id: 0,
 2116            next_inlay_id: 0,
 2117            code_action_providers,
 2118            available_code_actions: None,
 2119            code_actions_task: None,
 2120            quick_selection_highlight_task: None,
 2121            debounced_selection_highlight_task: None,
 2122            document_highlights_task: None,
 2123            linked_editing_range_task: None,
 2124            pending_rename: None,
 2125            searchable: !is_minimap,
 2126            cursor_shape: EditorSettings::get_global(cx)
 2127                .cursor_shape
 2128                .unwrap_or_default(),
 2129            current_line_highlight: None,
 2130            autoindent_mode: Some(AutoindentMode::EachLine),
 2131            collapse_matches: false,
 2132            workspace: None,
 2133            input_enabled: !is_minimap,
 2134            use_modal_editing: full_mode,
 2135            read_only: is_minimap,
 2136            use_autoclose: true,
 2137            use_auto_surround: true,
 2138            auto_replace_emoji_shortcode: false,
 2139            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2140            leader_id: None,
 2141            remote_id: None,
 2142            hover_state: HoverState::default(),
 2143            pending_mouse_down: None,
 2144            hovered_link_state: None,
 2145            edit_prediction_provider: None,
 2146            active_edit_prediction: None,
 2147            stale_edit_prediction_in_menu: None,
 2148            edit_prediction_preview: EditPredictionPreview::Inactive {
 2149                released_too_fast: false,
 2150            },
 2151            inline_diagnostics_enabled: full_mode,
 2152            diagnostics_enabled: full_mode,
 2153            word_completions_enabled: full_mode,
 2154            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2155            gutter_hovered: false,
 2156            pixel_position_of_newest_cursor: None,
 2157            last_bounds: None,
 2158            last_position_map: None,
 2159            expect_bounds_change: None,
 2160            gutter_dimensions: GutterDimensions::default(),
 2161            style: None,
 2162            show_cursor_names: false,
 2163            hovered_cursors: HashMap::default(),
 2164            next_editor_action_id: EditorActionId::default(),
 2165            editor_actions: Rc::default(),
 2166            edit_predictions_hidden_for_vim_mode: false,
 2167            show_edit_predictions_override: None,
 2168            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2169            edit_prediction_settings: EditPredictionSettings::Disabled,
 2170            edit_prediction_indent_conflict: false,
 2171            edit_prediction_requires_modifier_in_indent_conflict: true,
 2172            custom_context_menu: None,
 2173            show_git_blame_gutter: false,
 2174            show_git_blame_inline: false,
 2175            show_selection_menu: None,
 2176            show_git_blame_inline_delay_task: None,
 2177            git_blame_inline_enabled: full_mode
 2178                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2179            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2180            serialize_dirty_buffers: !is_minimap
 2181                && ProjectSettings::get_global(cx)
 2182                    .session
 2183                    .restore_unsaved_buffers,
 2184            blame: None,
 2185            blame_subscription: None,
 2186            tasks: BTreeMap::default(),
 2187
 2188            breakpoint_store,
 2189            gutter_breakpoint_indicator: (None, None),
 2190            hovered_diff_hunk_row: None,
 2191            _subscriptions: (!is_minimap)
 2192                .then(|| {
 2193                    vec![
 2194                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2195                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2196                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2197                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2198                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2199                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2200                        cx.observe_window_activation(window, |editor, window, cx| {
 2201                            let active = window.is_window_active();
 2202                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2203                                if active {
 2204                                    blink_manager.enable(cx);
 2205                                } else {
 2206                                    blink_manager.disable(cx);
 2207                                }
 2208                            });
 2209                            if active {
 2210                                editor.show_mouse_cursor(cx);
 2211                            }
 2212                        }),
 2213                    ]
 2214                })
 2215                .unwrap_or_default(),
 2216            tasks_update_task: None,
 2217            pull_diagnostics_task: Task::ready(()),
 2218            colors: None,
 2219            refresh_colors_task: Task::ready(()),
 2220            inlay_hints: None,
 2221            next_color_inlay_id: 0,
 2222            post_scroll_update: Task::ready(()),
 2223            linked_edit_ranges: Default::default(),
 2224            in_project_search: false,
 2225            previous_search_ranges: None,
 2226            breadcrumb_header: None,
 2227            focused_block: None,
 2228            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2229            addons: HashMap::default(),
 2230            registered_buffers: HashMap::default(),
 2231            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2232            selection_mark_mode: false,
 2233            toggle_fold_multiple_buffers: Task::ready(()),
 2234            serialize_selections: Task::ready(()),
 2235            serialize_folds: Task::ready(()),
 2236            text_style_refinement: None,
 2237            load_diff_task: load_uncommitted_diff,
 2238            temporary_diff_override: false,
 2239            mouse_cursor_hidden: false,
 2240            minimap: None,
 2241            hide_mouse_mode: EditorSettings::get_global(cx)
 2242                .hide_mouse
 2243                .unwrap_or_default(),
 2244            change_list: ChangeList::new(),
 2245            mode,
 2246            selection_drag_state: SelectionDragState::None,
 2247            folding_newlines: Task::ready(()),
 2248            lookup_key: None,
 2249        };
 2250
 2251        if is_minimap {
 2252            return editor;
 2253        }
 2254
 2255        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2256            editor
 2257                ._subscriptions
 2258                .push(cx.observe(breakpoints, |_, _, cx| {
 2259                    cx.notify();
 2260                }));
 2261        }
 2262        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2263        editor._subscriptions.extend(project_subscriptions);
 2264
 2265        editor._subscriptions.push(cx.subscribe_in(
 2266            &cx.entity(),
 2267            window,
 2268            |editor, _, e: &EditorEvent, window, cx| match e {
 2269                EditorEvent::ScrollPositionChanged { local, .. } => {
 2270                    if *local {
 2271                        let new_anchor = editor.scroll_manager.anchor();
 2272                        let snapshot = editor.snapshot(window, cx);
 2273                        editor.update_restoration_data(cx, move |data| {
 2274                            data.scroll_position = (
 2275                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2276                                new_anchor.offset,
 2277                            );
 2278                        });
 2279                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2280                        editor.inline_blame_popover.take();
 2281                    }
 2282                }
 2283                EditorEvent::Edited { .. } => {
 2284                    if !vim_enabled(cx) {
 2285                        let display_map = editor.display_snapshot(cx);
 2286                        let selections = editor.selections.all_adjusted_display(&display_map);
 2287                        let pop_state = editor
 2288                            .change_list
 2289                            .last()
 2290                            .map(|previous| {
 2291                                previous.len() == selections.len()
 2292                                    && previous.iter().enumerate().all(|(ix, p)| {
 2293                                        p.to_display_point(&display_map).row()
 2294                                            == selections[ix].head().row()
 2295                                    })
 2296                            })
 2297                            .unwrap_or(false);
 2298                        let new_positions = selections
 2299                            .into_iter()
 2300                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2301                            .collect();
 2302                        editor
 2303                            .change_list
 2304                            .push_to_change_list(pop_state, new_positions);
 2305                    }
 2306                }
 2307                _ => (),
 2308            },
 2309        ));
 2310
 2311        if let Some(dap_store) = editor
 2312            .project
 2313            .as_ref()
 2314            .map(|project| project.read(cx).dap_store())
 2315        {
 2316            let weak_editor = cx.weak_entity();
 2317
 2318            editor
 2319                ._subscriptions
 2320                .push(
 2321                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2322                        let session_entity = cx.entity();
 2323                        weak_editor
 2324                            .update(cx, |editor, cx| {
 2325                                editor._subscriptions.push(
 2326                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2327                                );
 2328                            })
 2329                            .ok();
 2330                    }),
 2331                );
 2332
 2333            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2334                editor
 2335                    ._subscriptions
 2336                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2337            }
 2338        }
 2339
 2340        // skip adding the initial selection to selection history
 2341        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2342        editor.end_selection(window, cx);
 2343        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2344
 2345        editor.scroll_manager.show_scrollbars(window, cx);
 2346        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2347
 2348        if full_mode {
 2349            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2350            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2351
 2352            if editor.git_blame_inline_enabled {
 2353                editor.start_git_blame_inline(false, window, cx);
 2354            }
 2355
 2356            editor.go_to_active_debug_line(window, cx);
 2357
 2358            editor.minimap =
 2359                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2360            editor.colors = Some(LspColorData::new(cx));
 2361            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2362
 2363            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2364                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2365            }
 2366            editor.update_lsp_data(None, window, cx);
 2367            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2368        }
 2369
 2370        editor
 2371    }
 2372
 2373    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2374        self.selections.display_map(cx)
 2375    }
 2376
 2377    pub fn deploy_mouse_context_menu(
 2378        &mut self,
 2379        position: gpui::Point<Pixels>,
 2380        context_menu: Entity<ContextMenu>,
 2381        window: &mut Window,
 2382        cx: &mut Context<Self>,
 2383    ) {
 2384        self.mouse_context_menu = Some(MouseContextMenu::new(
 2385            self,
 2386            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2387            context_menu,
 2388            window,
 2389            cx,
 2390        ));
 2391    }
 2392
 2393    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2394        self.mouse_context_menu
 2395            .as_ref()
 2396            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2397    }
 2398
 2399    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2400        if self
 2401            .selections
 2402            .pending_anchor()
 2403            .is_some_and(|pending_selection| {
 2404                let snapshot = self.buffer().read(cx).snapshot(cx);
 2405                pending_selection.range().includes(range, &snapshot)
 2406            })
 2407        {
 2408            return true;
 2409        }
 2410
 2411        self.selections
 2412            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2413            .into_iter()
 2414            .any(|selection| {
 2415                // This is needed to cover a corner case, if we just check for an existing
 2416                // selection in the fold range, having a cursor at the start of the fold
 2417                // marks it as selected. Non-empty selections don't cause this.
 2418                let length = selection.end - selection.start;
 2419                length > 0
 2420            })
 2421    }
 2422
 2423    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2424        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2425    }
 2426
 2427    fn key_context_internal(
 2428        &self,
 2429        has_active_edit_prediction: bool,
 2430        window: &mut Window,
 2431        cx: &mut App,
 2432    ) -> KeyContext {
 2433        let mut key_context = KeyContext::new_with_defaults();
 2434        key_context.add("Editor");
 2435        let mode = match self.mode {
 2436            EditorMode::SingleLine => "single_line",
 2437            EditorMode::AutoHeight { .. } => "auto_height",
 2438            EditorMode::Minimap { .. } => "minimap",
 2439            EditorMode::Full { .. } => "full",
 2440        };
 2441
 2442        if EditorSettings::jupyter_enabled(cx) {
 2443            key_context.add("jupyter");
 2444        }
 2445
 2446        key_context.set("mode", mode);
 2447        if self.pending_rename.is_some() {
 2448            key_context.add("renaming");
 2449        }
 2450
 2451        match self.context_menu.borrow().as_ref() {
 2452            Some(CodeContextMenu::Completions(menu)) => {
 2453                if menu.visible() {
 2454                    key_context.add("menu");
 2455                    key_context.add("showing_completions");
 2456                }
 2457            }
 2458            Some(CodeContextMenu::CodeActions(menu)) => {
 2459                if menu.visible() {
 2460                    key_context.add("menu");
 2461                    key_context.add("showing_code_actions")
 2462                }
 2463            }
 2464            None => {}
 2465        }
 2466
 2467        if self.signature_help_state.has_multiple_signatures() {
 2468            key_context.add("showing_signature_help");
 2469        }
 2470
 2471        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2472        if !self.focus_handle(cx).contains_focused(window, cx)
 2473            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2474        {
 2475            for addon in self.addons.values() {
 2476                addon.extend_key_context(&mut key_context, cx)
 2477            }
 2478        }
 2479
 2480        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2481            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2482                Some(
 2483                    file.full_path(cx)
 2484                        .extension()?
 2485                        .to_string_lossy()
 2486                        .into_owned(),
 2487                )
 2488            }) {
 2489                key_context.set("extension", extension);
 2490            }
 2491        } else {
 2492            key_context.add("multibuffer");
 2493        }
 2494
 2495        if has_active_edit_prediction {
 2496            if self.edit_prediction_in_conflict() {
 2497                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2498            } else {
 2499                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2500                key_context.add("copilot_suggestion");
 2501            }
 2502        }
 2503
 2504        if self.selection_mark_mode {
 2505            key_context.add("selection_mode");
 2506        }
 2507
 2508        let disjoint = self.selections.disjoint_anchors();
 2509        let snapshot = self.snapshot(window, cx);
 2510        let snapshot = snapshot.buffer_snapshot();
 2511        if self.mode == EditorMode::SingleLine
 2512            && let [selection] = disjoint
 2513            && selection.start == selection.end
 2514            && selection.end.to_offset(snapshot) == snapshot.len()
 2515        {
 2516            key_context.add("end_of_input");
 2517        }
 2518
 2519        key_context
 2520    }
 2521
 2522    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2523        self.last_bounds.as_ref()
 2524    }
 2525
 2526    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2527        if self.mouse_cursor_hidden {
 2528            self.mouse_cursor_hidden = false;
 2529            cx.notify();
 2530        }
 2531    }
 2532
 2533    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2534        let hide_mouse_cursor = match origin {
 2535            HideMouseCursorOrigin::TypingAction => {
 2536                matches!(
 2537                    self.hide_mouse_mode,
 2538                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2539                )
 2540            }
 2541            HideMouseCursorOrigin::MovementAction => {
 2542                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2543            }
 2544        };
 2545        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2546            self.mouse_cursor_hidden = hide_mouse_cursor;
 2547            cx.notify();
 2548        }
 2549    }
 2550
 2551    pub fn edit_prediction_in_conflict(&self) -> bool {
 2552        if !self.show_edit_predictions_in_menu() {
 2553            return false;
 2554        }
 2555
 2556        let showing_completions = self
 2557            .context_menu
 2558            .borrow()
 2559            .as_ref()
 2560            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2561
 2562        showing_completions
 2563            || self.edit_prediction_requires_modifier()
 2564            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2565            // bindings to insert tab characters.
 2566            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2567    }
 2568
 2569    pub fn accept_edit_prediction_keybind(
 2570        &self,
 2571        accept_partial: bool,
 2572        window: &mut Window,
 2573        cx: &mut App,
 2574    ) -> AcceptEditPredictionBinding {
 2575        let key_context = self.key_context_internal(true, window, cx);
 2576        let in_conflict = self.edit_prediction_in_conflict();
 2577
 2578        let bindings = if accept_partial {
 2579            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2580        } else {
 2581            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2582        };
 2583
 2584        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2585        // just the first one.
 2586        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2587            !in_conflict
 2588                || binding
 2589                    .keystrokes()
 2590                    .first()
 2591                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2592        }))
 2593    }
 2594
 2595    pub fn new_file(
 2596        workspace: &mut Workspace,
 2597        _: &workspace::NewFile,
 2598        window: &mut Window,
 2599        cx: &mut Context<Workspace>,
 2600    ) {
 2601        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2602            "Failed to create buffer",
 2603            window,
 2604            cx,
 2605            |e, _, _| match e.error_code() {
 2606                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2607                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2608                e.error_tag("required").unwrap_or("the latest version")
 2609            )),
 2610                _ => None,
 2611            },
 2612        );
 2613    }
 2614
 2615    pub fn new_in_workspace(
 2616        workspace: &mut Workspace,
 2617        window: &mut Window,
 2618        cx: &mut Context<Workspace>,
 2619    ) -> Task<Result<Entity<Editor>>> {
 2620        let project = workspace.project().clone();
 2621        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2622
 2623        cx.spawn_in(window, async move |workspace, cx| {
 2624            let buffer = create.await?;
 2625            workspace.update_in(cx, |workspace, window, cx| {
 2626                let editor =
 2627                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2628                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2629                editor
 2630            })
 2631        })
 2632    }
 2633
 2634    fn new_file_vertical(
 2635        workspace: &mut Workspace,
 2636        _: &workspace::NewFileSplitVertical,
 2637        window: &mut Window,
 2638        cx: &mut Context<Workspace>,
 2639    ) {
 2640        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2641    }
 2642
 2643    fn new_file_horizontal(
 2644        workspace: &mut Workspace,
 2645        _: &workspace::NewFileSplitHorizontal,
 2646        window: &mut Window,
 2647        cx: &mut Context<Workspace>,
 2648    ) {
 2649        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2650    }
 2651
 2652    fn new_file_split(
 2653        workspace: &mut Workspace,
 2654        action: &workspace::NewFileSplit,
 2655        window: &mut Window,
 2656        cx: &mut Context<Workspace>,
 2657    ) {
 2658        Self::new_file_in_direction(workspace, action.0, window, cx)
 2659    }
 2660
 2661    fn new_file_in_direction(
 2662        workspace: &mut Workspace,
 2663        direction: SplitDirection,
 2664        window: &mut Window,
 2665        cx: &mut Context<Workspace>,
 2666    ) {
 2667        let project = workspace.project().clone();
 2668        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2669
 2670        cx.spawn_in(window, async move |workspace, cx| {
 2671            let buffer = create.await?;
 2672            workspace.update_in(cx, move |workspace, window, cx| {
 2673                workspace.split_item(
 2674                    direction,
 2675                    Box::new(
 2676                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2677                    ),
 2678                    window,
 2679                    cx,
 2680                )
 2681            })?;
 2682            anyhow::Ok(())
 2683        })
 2684        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2685            match e.error_code() {
 2686                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2687                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2688                e.error_tag("required").unwrap_or("the latest version")
 2689            )),
 2690                _ => None,
 2691            }
 2692        });
 2693    }
 2694
 2695    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2696        self.leader_id
 2697    }
 2698
 2699    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2700        &self.buffer
 2701    }
 2702
 2703    pub fn project(&self) -> Option<&Entity<Project>> {
 2704        self.project.as_ref()
 2705    }
 2706
 2707    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2708        self.workspace.as_ref()?.0.upgrade()
 2709    }
 2710
 2711    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2712        self.buffer().read(cx).title(cx)
 2713    }
 2714
 2715    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2716        let git_blame_gutter_max_author_length = self
 2717            .render_git_blame_gutter(cx)
 2718            .then(|| {
 2719                if let Some(blame) = self.blame.as_ref() {
 2720                    let max_author_length =
 2721                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2722                    Some(max_author_length)
 2723                } else {
 2724                    None
 2725                }
 2726            })
 2727            .flatten();
 2728
 2729        EditorSnapshot {
 2730            mode: self.mode.clone(),
 2731            show_gutter: self.show_gutter,
 2732            show_line_numbers: self.show_line_numbers,
 2733            show_git_diff_gutter: self.show_git_diff_gutter,
 2734            show_code_actions: self.show_code_actions,
 2735            show_runnables: self.show_runnables,
 2736            show_breakpoints: self.show_breakpoints,
 2737            git_blame_gutter_max_author_length,
 2738            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2739            placeholder_display_snapshot: self
 2740                .placeholder_display_map
 2741                .as_ref()
 2742                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2743            scroll_anchor: self.scroll_manager.anchor(),
 2744            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2745            is_focused: self.focus_handle.is_focused(window),
 2746            current_line_highlight: self
 2747                .current_line_highlight
 2748                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2749            gutter_hovered: self.gutter_hovered,
 2750        }
 2751    }
 2752
 2753    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2754        self.buffer.read(cx).language_at(point, cx)
 2755    }
 2756
 2757    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2758        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2759    }
 2760
 2761    pub fn active_excerpt(
 2762        &self,
 2763        cx: &App,
 2764    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2765        self.buffer
 2766            .read(cx)
 2767            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2768    }
 2769
 2770    pub fn mode(&self) -> &EditorMode {
 2771        &self.mode
 2772    }
 2773
 2774    pub fn set_mode(&mut self, mode: EditorMode) {
 2775        self.mode = mode;
 2776    }
 2777
 2778    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2779        self.collaboration_hub.as_deref()
 2780    }
 2781
 2782    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2783        self.collaboration_hub = Some(hub);
 2784    }
 2785
 2786    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2787        self.in_project_search = in_project_search;
 2788    }
 2789
 2790    pub fn set_custom_context_menu(
 2791        &mut self,
 2792        f: impl 'static
 2793        + Fn(
 2794            &mut Self,
 2795            DisplayPoint,
 2796            &mut Window,
 2797            &mut Context<Self>,
 2798        ) -> Option<Entity<ui::ContextMenu>>,
 2799    ) {
 2800        self.custom_context_menu = Some(Box::new(f))
 2801    }
 2802
 2803    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2804        self.completion_provider = provider;
 2805    }
 2806
 2807    #[cfg(any(test, feature = "test-support"))]
 2808    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2809        self.completion_provider.clone()
 2810    }
 2811
 2812    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2813        self.semantics_provider.clone()
 2814    }
 2815
 2816    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2817        self.semantics_provider = provider;
 2818    }
 2819
 2820    pub fn set_edit_prediction_provider<T>(
 2821        &mut self,
 2822        provider: Option<Entity<T>>,
 2823        window: &mut Window,
 2824        cx: &mut Context<Self>,
 2825    ) where
 2826        T: EditPredictionProvider,
 2827    {
 2828        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2829            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2830                if this.focus_handle.is_focused(window) {
 2831                    this.update_visible_edit_prediction(window, cx);
 2832                }
 2833            }),
 2834            provider: Arc::new(provider),
 2835        });
 2836        self.update_edit_prediction_settings(cx);
 2837        self.refresh_edit_prediction(false, false, window, cx);
 2838    }
 2839
 2840    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2841        self.placeholder_display_map
 2842            .as_ref()
 2843            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2844    }
 2845
 2846    pub fn set_placeholder_text(
 2847        &mut self,
 2848        placeholder_text: &str,
 2849        window: &mut Window,
 2850        cx: &mut Context<Self>,
 2851    ) {
 2852        let multibuffer = cx
 2853            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2854
 2855        let style = window.text_style();
 2856
 2857        self.placeholder_display_map = Some(cx.new(|cx| {
 2858            DisplayMap::new(
 2859                multibuffer,
 2860                style.font(),
 2861                style.font_size.to_pixels(window.rem_size()),
 2862                None,
 2863                FILE_HEADER_HEIGHT,
 2864                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2865                Default::default(),
 2866                DiagnosticSeverity::Off,
 2867                cx,
 2868            )
 2869        }));
 2870        cx.notify();
 2871    }
 2872
 2873    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2874        self.cursor_shape = cursor_shape;
 2875
 2876        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2877        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2878
 2879        cx.notify();
 2880    }
 2881
 2882    pub fn set_current_line_highlight(
 2883        &mut self,
 2884        current_line_highlight: Option<CurrentLineHighlight>,
 2885    ) {
 2886        self.current_line_highlight = current_line_highlight;
 2887    }
 2888
 2889    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2890        self.collapse_matches = collapse_matches;
 2891    }
 2892
 2893    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2894        if self.collapse_matches {
 2895            return range.start..range.start;
 2896        }
 2897        range.clone()
 2898    }
 2899
 2900    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2901        if self.display_map.read(cx).clip_at_line_ends != clip {
 2902            self.display_map
 2903                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2904        }
 2905    }
 2906
 2907    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2908        self.input_enabled = input_enabled;
 2909    }
 2910
 2911    pub fn set_edit_predictions_hidden_for_vim_mode(
 2912        &mut self,
 2913        hidden: bool,
 2914        window: &mut Window,
 2915        cx: &mut Context<Self>,
 2916    ) {
 2917        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2918            self.edit_predictions_hidden_for_vim_mode = hidden;
 2919            if hidden {
 2920                self.update_visible_edit_prediction(window, cx);
 2921            } else {
 2922                self.refresh_edit_prediction(true, false, window, cx);
 2923            }
 2924        }
 2925    }
 2926
 2927    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2928        self.menu_edit_predictions_policy = value;
 2929    }
 2930
 2931    pub fn set_autoindent(&mut self, autoindent: bool) {
 2932        if autoindent {
 2933            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2934        } else {
 2935            self.autoindent_mode = None;
 2936        }
 2937    }
 2938
 2939    pub fn read_only(&self, cx: &App) -> bool {
 2940        self.read_only || self.buffer.read(cx).read_only()
 2941    }
 2942
 2943    pub fn set_read_only(&mut self, read_only: bool) {
 2944        self.read_only = read_only;
 2945    }
 2946
 2947    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2948        self.use_autoclose = autoclose;
 2949    }
 2950
 2951    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2952        self.use_auto_surround = auto_surround;
 2953    }
 2954
 2955    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2956        self.auto_replace_emoji_shortcode = auto_replace;
 2957    }
 2958
 2959    pub fn toggle_edit_predictions(
 2960        &mut self,
 2961        _: &ToggleEditPrediction,
 2962        window: &mut Window,
 2963        cx: &mut Context<Self>,
 2964    ) {
 2965        if self.show_edit_predictions_override.is_some() {
 2966            self.set_show_edit_predictions(None, window, cx);
 2967        } else {
 2968            let show_edit_predictions = !self.edit_predictions_enabled();
 2969            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2970        }
 2971    }
 2972
 2973    pub fn set_show_edit_predictions(
 2974        &mut self,
 2975        show_edit_predictions: Option<bool>,
 2976        window: &mut Window,
 2977        cx: &mut Context<Self>,
 2978    ) {
 2979        self.show_edit_predictions_override = show_edit_predictions;
 2980        self.update_edit_prediction_settings(cx);
 2981
 2982        if let Some(false) = show_edit_predictions {
 2983            self.discard_edit_prediction(false, cx);
 2984        } else {
 2985            self.refresh_edit_prediction(false, true, window, cx);
 2986        }
 2987    }
 2988
 2989    fn edit_predictions_disabled_in_scope(
 2990        &self,
 2991        buffer: &Entity<Buffer>,
 2992        buffer_position: language::Anchor,
 2993        cx: &App,
 2994    ) -> bool {
 2995        let snapshot = buffer.read(cx).snapshot();
 2996        let settings = snapshot.settings_at(buffer_position, cx);
 2997
 2998        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2999            return false;
 3000        };
 3001
 3002        scope.override_name().is_some_and(|scope_name| {
 3003            settings
 3004                .edit_predictions_disabled_in
 3005                .iter()
 3006                .any(|s| s == scope_name)
 3007        })
 3008    }
 3009
 3010    pub fn set_use_modal_editing(&mut self, to: bool) {
 3011        self.use_modal_editing = to;
 3012    }
 3013
 3014    pub fn use_modal_editing(&self) -> bool {
 3015        self.use_modal_editing
 3016    }
 3017
 3018    fn selections_did_change(
 3019        &mut self,
 3020        local: bool,
 3021        old_cursor_position: &Anchor,
 3022        effects: SelectionEffects,
 3023        window: &mut Window,
 3024        cx: &mut Context<Self>,
 3025    ) {
 3026        window.invalidate_character_coordinates();
 3027
 3028        // Copy selections to primary selection buffer
 3029        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3030        if local {
 3031            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3032            let buffer_handle = self.buffer.read(cx).read(cx);
 3033
 3034            let mut text = String::new();
 3035            for (index, selection) in selections.iter().enumerate() {
 3036                let text_for_selection = buffer_handle
 3037                    .text_for_range(selection.start..selection.end)
 3038                    .collect::<String>();
 3039
 3040                text.push_str(&text_for_selection);
 3041                if index != selections.len() - 1 {
 3042                    text.push('\n');
 3043                }
 3044            }
 3045
 3046            if !text.is_empty() {
 3047                cx.write_to_primary(ClipboardItem::new_string(text));
 3048            }
 3049        }
 3050
 3051        let selection_anchors = self.selections.disjoint_anchors_arc();
 3052
 3053        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3054            self.buffer.update(cx, |buffer, cx| {
 3055                buffer.set_active_selections(
 3056                    &selection_anchors,
 3057                    self.selections.line_mode(),
 3058                    self.cursor_shape,
 3059                    cx,
 3060                )
 3061            });
 3062        }
 3063        let display_map = self
 3064            .display_map
 3065            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3066        let buffer = display_map.buffer_snapshot();
 3067        if self.selections.count() == 1 {
 3068            self.add_selections_state = None;
 3069        }
 3070        self.select_next_state = None;
 3071        self.select_prev_state = None;
 3072        self.select_syntax_node_history.try_clear();
 3073        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3074        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3075        self.take_rename(false, window, cx);
 3076
 3077        let newest_selection = self.selections.newest_anchor();
 3078        let new_cursor_position = newest_selection.head();
 3079        let selection_start = newest_selection.start;
 3080
 3081        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3082            self.push_to_nav_history(
 3083                *old_cursor_position,
 3084                Some(new_cursor_position.to_point(buffer)),
 3085                false,
 3086                effects.nav_history == Some(true),
 3087                cx,
 3088            );
 3089        }
 3090
 3091        if local {
 3092            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3093                self.register_buffer(buffer_id, cx);
 3094            }
 3095
 3096            let mut context_menu = self.context_menu.borrow_mut();
 3097            let completion_menu = match context_menu.as_ref() {
 3098                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3099                Some(CodeContextMenu::CodeActions(_)) => {
 3100                    *context_menu = None;
 3101                    None
 3102                }
 3103                None => None,
 3104            };
 3105            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3106            drop(context_menu);
 3107
 3108            if effects.completions
 3109                && let Some(completion_position) = completion_position
 3110            {
 3111                let start_offset = selection_start.to_offset(buffer);
 3112                let position_matches = start_offset == completion_position.to_offset(buffer);
 3113                let continue_showing = if position_matches {
 3114                    if self.snippet_stack.is_empty() {
 3115                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3116                            == Some(CharKind::Word)
 3117                    } else {
 3118                        // Snippet choices can be shown even when the cursor is in whitespace.
 3119                        // Dismissing the menu with actions like backspace is handled by
 3120                        // invalidation regions.
 3121                        true
 3122                    }
 3123                } else {
 3124                    false
 3125                };
 3126
 3127                if continue_showing {
 3128                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3129                } else {
 3130                    self.hide_context_menu(window, cx);
 3131                }
 3132            }
 3133
 3134            hide_hover(self, cx);
 3135
 3136            if old_cursor_position.to_display_point(&display_map).row()
 3137                != new_cursor_position.to_display_point(&display_map).row()
 3138            {
 3139                self.available_code_actions.take();
 3140            }
 3141            self.refresh_code_actions(window, cx);
 3142            self.refresh_document_highlights(cx);
 3143            refresh_linked_ranges(self, window, cx);
 3144
 3145            self.refresh_selected_text_highlights(false, window, cx);
 3146            refresh_matching_bracket_highlights(self, cx);
 3147            self.update_visible_edit_prediction(window, cx);
 3148            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3149            self.inline_blame_popover.take();
 3150            if self.git_blame_inline_enabled {
 3151                self.start_inline_blame_timer(window, cx);
 3152            }
 3153        }
 3154
 3155        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3156        cx.emit(EditorEvent::SelectionsChanged { local });
 3157
 3158        let selections = &self.selections.disjoint_anchors_arc();
 3159        if selections.len() == 1 {
 3160            cx.emit(SearchEvent::ActiveMatchChanged)
 3161        }
 3162        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3163            let inmemory_selections = selections
 3164                .iter()
 3165                .map(|s| {
 3166                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3167                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3168                })
 3169                .collect();
 3170            self.update_restoration_data(cx, |data| {
 3171                data.selections = inmemory_selections;
 3172            });
 3173
 3174            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3175                && let Some(workspace_id) =
 3176                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3177            {
 3178                let snapshot = self.buffer().read(cx).snapshot(cx);
 3179                let selections = selections.clone();
 3180                let background_executor = cx.background_executor().clone();
 3181                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3182                self.serialize_selections = cx.background_spawn(async move {
 3183                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3184                    let db_selections = selections
 3185                        .iter()
 3186                        .map(|selection| {
 3187                            (
 3188                                selection.start.to_offset(&snapshot),
 3189                                selection.end.to_offset(&snapshot),
 3190                            )
 3191                        })
 3192                        .collect();
 3193
 3194                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3195                        .await
 3196                        .with_context(|| {
 3197                            format!(
 3198                                "persisting editor selections for editor {editor_id}, \
 3199                                workspace {workspace_id:?}"
 3200                            )
 3201                        })
 3202                        .log_err();
 3203                });
 3204            }
 3205        }
 3206
 3207        cx.notify();
 3208    }
 3209
 3210    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3211        use text::ToOffset as _;
 3212        use text::ToPoint as _;
 3213
 3214        if self.mode.is_minimap()
 3215            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3216        {
 3217            return;
 3218        }
 3219
 3220        if !self.buffer().read(cx).is_singleton() {
 3221            return;
 3222        }
 3223
 3224        let display_snapshot = self
 3225            .display_map
 3226            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3227        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3228            return;
 3229        };
 3230        let inmemory_folds = display_snapshot
 3231            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3232            .map(|fold| {
 3233                fold.range.start.text_anchor.to_point(&snapshot)
 3234                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3235            })
 3236            .collect();
 3237        self.update_restoration_data(cx, |data| {
 3238            data.folds = inmemory_folds;
 3239        });
 3240
 3241        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3242            return;
 3243        };
 3244        let background_executor = cx.background_executor().clone();
 3245        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3246        let db_folds = display_snapshot
 3247            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3248            .map(|fold| {
 3249                (
 3250                    fold.range.start.text_anchor.to_offset(&snapshot),
 3251                    fold.range.end.text_anchor.to_offset(&snapshot),
 3252                )
 3253            })
 3254            .collect();
 3255        self.serialize_folds = cx.background_spawn(async move {
 3256            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3257            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3258                .await
 3259                .with_context(|| {
 3260                    format!(
 3261                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3262                    )
 3263                })
 3264                .log_err();
 3265        });
 3266    }
 3267
 3268    pub fn sync_selections(
 3269        &mut self,
 3270        other: Entity<Editor>,
 3271        cx: &mut Context<Self>,
 3272    ) -> gpui::Subscription {
 3273        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3274        if !other_selections.is_empty() {
 3275            self.selections.change_with(cx, |selections| {
 3276                selections.select_anchors(other_selections);
 3277            });
 3278        }
 3279
 3280        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3281            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3282                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3283                if other_selections.is_empty() {
 3284                    return;
 3285                }
 3286                this.selections.change_with(cx, |selections| {
 3287                    selections.select_anchors(other_selections);
 3288                });
 3289            }
 3290        });
 3291
 3292        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3293            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3294                let these_selections = this.selections.disjoint_anchors().to_vec();
 3295                if these_selections.is_empty() {
 3296                    return;
 3297                }
 3298                other.update(cx, |other_editor, cx| {
 3299                    other_editor.selections.change_with(cx, |selections| {
 3300                        selections.select_anchors(these_selections);
 3301                    })
 3302                });
 3303            }
 3304        });
 3305
 3306        Subscription::join(other_subscription, this_subscription)
 3307    }
 3308
 3309    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3310    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3311    /// effects of selection change occur at the end of the transaction.
 3312    pub fn change_selections<R>(
 3313        &mut self,
 3314        effects: SelectionEffects,
 3315        window: &mut Window,
 3316        cx: &mut Context<Self>,
 3317        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3318    ) -> R {
 3319        if let Some(state) = &mut self.deferred_selection_effects_state {
 3320            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3321            state.effects.completions = effects.completions;
 3322            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3323            let (changed, result) = self.selections.change_with(cx, change);
 3324            state.changed |= changed;
 3325            return result;
 3326        }
 3327        let mut state = DeferredSelectionEffectsState {
 3328            changed: false,
 3329            effects,
 3330            old_cursor_position: self.selections.newest_anchor().head(),
 3331            history_entry: SelectionHistoryEntry {
 3332                selections: self.selections.disjoint_anchors_arc(),
 3333                select_next_state: self.select_next_state.clone(),
 3334                select_prev_state: self.select_prev_state.clone(),
 3335                add_selections_state: self.add_selections_state.clone(),
 3336            },
 3337        };
 3338        let (changed, result) = self.selections.change_with(cx, change);
 3339        state.changed = state.changed || changed;
 3340        if self.defer_selection_effects {
 3341            self.deferred_selection_effects_state = Some(state);
 3342        } else {
 3343            self.apply_selection_effects(state, window, cx);
 3344        }
 3345        result
 3346    }
 3347
 3348    /// Defers the effects of selection change, so that the effects of multiple calls to
 3349    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3350    /// to selection history and the state of popovers based on selection position aren't
 3351    /// erroneously updated.
 3352    pub fn with_selection_effects_deferred<R>(
 3353        &mut self,
 3354        window: &mut Window,
 3355        cx: &mut Context<Self>,
 3356        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3357    ) -> R {
 3358        let already_deferred = self.defer_selection_effects;
 3359        self.defer_selection_effects = true;
 3360        let result = update(self, window, cx);
 3361        if !already_deferred {
 3362            self.defer_selection_effects = false;
 3363            if let Some(state) = self.deferred_selection_effects_state.take() {
 3364                self.apply_selection_effects(state, window, cx);
 3365            }
 3366        }
 3367        result
 3368    }
 3369
 3370    fn apply_selection_effects(
 3371        &mut self,
 3372        state: DeferredSelectionEffectsState,
 3373        window: &mut Window,
 3374        cx: &mut Context<Self>,
 3375    ) {
 3376        if state.changed {
 3377            self.selection_history.push(state.history_entry);
 3378
 3379            if let Some(autoscroll) = state.effects.scroll {
 3380                self.request_autoscroll(autoscroll, cx);
 3381            }
 3382
 3383            let old_cursor_position = &state.old_cursor_position;
 3384
 3385            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3386
 3387            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3388                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3389            }
 3390        }
 3391    }
 3392
 3393    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3394    where
 3395        I: IntoIterator<Item = (Range<S>, T)>,
 3396        S: ToOffset,
 3397        T: Into<Arc<str>>,
 3398    {
 3399        if self.read_only(cx) {
 3400            return;
 3401        }
 3402
 3403        self.buffer
 3404            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3405    }
 3406
 3407    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3408    where
 3409        I: IntoIterator<Item = (Range<S>, T)>,
 3410        S: ToOffset,
 3411        T: Into<Arc<str>>,
 3412    {
 3413        if self.read_only(cx) {
 3414            return;
 3415        }
 3416
 3417        self.buffer.update(cx, |buffer, cx| {
 3418            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3419        });
 3420    }
 3421
 3422    pub fn edit_with_block_indent<I, S, T>(
 3423        &mut self,
 3424        edits: I,
 3425        original_indent_columns: Vec<Option<u32>>,
 3426        cx: &mut Context<Self>,
 3427    ) where
 3428        I: IntoIterator<Item = (Range<S>, T)>,
 3429        S: ToOffset,
 3430        T: Into<Arc<str>>,
 3431    {
 3432        if self.read_only(cx) {
 3433            return;
 3434        }
 3435
 3436        self.buffer.update(cx, |buffer, cx| {
 3437            buffer.edit(
 3438                edits,
 3439                Some(AutoindentMode::Block {
 3440                    original_indent_columns,
 3441                }),
 3442                cx,
 3443            )
 3444        });
 3445    }
 3446
 3447    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3448        self.hide_context_menu(window, cx);
 3449
 3450        match phase {
 3451            SelectPhase::Begin {
 3452                position,
 3453                add,
 3454                click_count,
 3455            } => self.begin_selection(position, add, click_count, window, cx),
 3456            SelectPhase::BeginColumnar {
 3457                position,
 3458                goal_column,
 3459                reset,
 3460                mode,
 3461            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3462            SelectPhase::Extend {
 3463                position,
 3464                click_count,
 3465            } => self.extend_selection(position, click_count, window, cx),
 3466            SelectPhase::Update {
 3467                position,
 3468                goal_column,
 3469                scroll_delta,
 3470            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3471            SelectPhase::End => self.end_selection(window, cx),
 3472        }
 3473    }
 3474
 3475    fn extend_selection(
 3476        &mut self,
 3477        position: DisplayPoint,
 3478        click_count: usize,
 3479        window: &mut Window,
 3480        cx: &mut Context<Self>,
 3481    ) {
 3482        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3483        let tail = self.selections.newest::<usize>(&display_map).tail();
 3484        let click_count = click_count.max(match self.selections.select_mode() {
 3485            SelectMode::Character => 1,
 3486            SelectMode::Word(_) => 2,
 3487            SelectMode::Line(_) => 3,
 3488            SelectMode::All => 4,
 3489        });
 3490        self.begin_selection(position, false, click_count, window, cx);
 3491
 3492        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3493
 3494        let current_selection = match self.selections.select_mode() {
 3495            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3496            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3497        };
 3498
 3499        let mut pending_selection = self
 3500            .selections
 3501            .pending_anchor()
 3502            .cloned()
 3503            .expect("extend_selection not called with pending selection");
 3504
 3505        if pending_selection
 3506            .start
 3507            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3508            == Ordering::Greater
 3509        {
 3510            pending_selection.start = current_selection.start;
 3511        }
 3512        if pending_selection
 3513            .end
 3514            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3515            == Ordering::Less
 3516        {
 3517            pending_selection.end = current_selection.end;
 3518            pending_selection.reversed = true;
 3519        }
 3520
 3521        let mut pending_mode = self.selections.pending_mode().unwrap();
 3522        match &mut pending_mode {
 3523            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3524            _ => {}
 3525        }
 3526
 3527        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3528            SelectionEffects::scroll(Autoscroll::fit())
 3529        } else {
 3530            SelectionEffects::no_scroll()
 3531        };
 3532
 3533        self.change_selections(effects, window, cx, |s| {
 3534            s.set_pending(pending_selection.clone(), pending_mode);
 3535            s.set_is_extending(true);
 3536        });
 3537    }
 3538
 3539    fn begin_selection(
 3540        &mut self,
 3541        position: DisplayPoint,
 3542        add: bool,
 3543        click_count: usize,
 3544        window: &mut Window,
 3545        cx: &mut Context<Self>,
 3546    ) {
 3547        if !self.focus_handle.is_focused(window) {
 3548            self.last_focused_descendant = None;
 3549            window.focus(&self.focus_handle);
 3550        }
 3551
 3552        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3553        let buffer = display_map.buffer_snapshot();
 3554        let position = display_map.clip_point(position, Bias::Left);
 3555
 3556        let start;
 3557        let end;
 3558        let mode;
 3559        let mut auto_scroll;
 3560        match click_count {
 3561            1 => {
 3562                start = buffer.anchor_before(position.to_point(&display_map));
 3563                end = start;
 3564                mode = SelectMode::Character;
 3565                auto_scroll = true;
 3566            }
 3567            2 => {
 3568                let position = display_map
 3569                    .clip_point(position, Bias::Left)
 3570                    .to_offset(&display_map, Bias::Left);
 3571                let (range, _) = buffer.surrounding_word(position, None);
 3572                start = buffer.anchor_before(range.start);
 3573                end = buffer.anchor_before(range.end);
 3574                mode = SelectMode::Word(start..end);
 3575                auto_scroll = true;
 3576            }
 3577            3 => {
 3578                let position = display_map
 3579                    .clip_point(position, Bias::Left)
 3580                    .to_point(&display_map);
 3581                let line_start = display_map.prev_line_boundary(position).0;
 3582                let next_line_start = buffer.clip_point(
 3583                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3584                    Bias::Left,
 3585                );
 3586                start = buffer.anchor_before(line_start);
 3587                end = buffer.anchor_before(next_line_start);
 3588                mode = SelectMode::Line(start..end);
 3589                auto_scroll = true;
 3590            }
 3591            _ => {
 3592                start = buffer.anchor_before(0);
 3593                end = buffer.anchor_before(buffer.len());
 3594                mode = SelectMode::All;
 3595                auto_scroll = false;
 3596            }
 3597        }
 3598        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3599
 3600        let point_to_delete: Option<usize> = {
 3601            let selected_points: Vec<Selection<Point>> =
 3602                self.selections.disjoint_in_range(start..end, &display_map);
 3603
 3604            if !add || click_count > 1 {
 3605                None
 3606            } else if !selected_points.is_empty() {
 3607                Some(selected_points[0].id)
 3608            } else {
 3609                let clicked_point_already_selected =
 3610                    self.selections.disjoint_anchors().iter().find(|selection| {
 3611                        selection.start.to_point(buffer) == start.to_point(buffer)
 3612                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3613                    });
 3614
 3615                clicked_point_already_selected.map(|selection| selection.id)
 3616            }
 3617        };
 3618
 3619        let selections_count = self.selections.count();
 3620        let effects = if auto_scroll {
 3621            SelectionEffects::default()
 3622        } else {
 3623            SelectionEffects::no_scroll()
 3624        };
 3625
 3626        self.change_selections(effects, window, cx, |s| {
 3627            if let Some(point_to_delete) = point_to_delete {
 3628                s.delete(point_to_delete);
 3629
 3630                if selections_count == 1 {
 3631                    s.set_pending_anchor_range(start..end, mode);
 3632                }
 3633            } else {
 3634                if !add {
 3635                    s.clear_disjoint();
 3636                }
 3637
 3638                s.set_pending_anchor_range(start..end, mode);
 3639            }
 3640        });
 3641    }
 3642
 3643    fn begin_columnar_selection(
 3644        &mut self,
 3645        position: DisplayPoint,
 3646        goal_column: u32,
 3647        reset: bool,
 3648        mode: ColumnarMode,
 3649        window: &mut Window,
 3650        cx: &mut Context<Self>,
 3651    ) {
 3652        if !self.focus_handle.is_focused(window) {
 3653            self.last_focused_descendant = None;
 3654            window.focus(&self.focus_handle);
 3655        }
 3656
 3657        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3658
 3659        if reset {
 3660            let pointer_position = display_map
 3661                .buffer_snapshot()
 3662                .anchor_before(position.to_point(&display_map));
 3663
 3664            self.change_selections(
 3665                SelectionEffects::scroll(Autoscroll::newest()),
 3666                window,
 3667                cx,
 3668                |s| {
 3669                    s.clear_disjoint();
 3670                    s.set_pending_anchor_range(
 3671                        pointer_position..pointer_position,
 3672                        SelectMode::Character,
 3673                    );
 3674                },
 3675            );
 3676        };
 3677
 3678        let tail = self.selections.newest::<Point>(&display_map).tail();
 3679        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3680        self.columnar_selection_state = match mode {
 3681            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3682                selection_tail: selection_anchor,
 3683                display_point: if reset {
 3684                    if position.column() != goal_column {
 3685                        Some(DisplayPoint::new(position.row(), goal_column))
 3686                    } else {
 3687                        None
 3688                    }
 3689                } else {
 3690                    None
 3691                },
 3692            }),
 3693            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3694                selection_tail: selection_anchor,
 3695            }),
 3696        };
 3697
 3698        if !reset {
 3699            self.select_columns(position, goal_column, &display_map, window, cx);
 3700        }
 3701    }
 3702
 3703    fn update_selection(
 3704        &mut self,
 3705        position: DisplayPoint,
 3706        goal_column: u32,
 3707        scroll_delta: gpui::Point<f32>,
 3708        window: &mut Window,
 3709        cx: &mut Context<Self>,
 3710    ) {
 3711        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3712
 3713        if self.columnar_selection_state.is_some() {
 3714            self.select_columns(position, goal_column, &display_map, window, cx);
 3715        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3716            let buffer = display_map.buffer_snapshot();
 3717            let head;
 3718            let tail;
 3719            let mode = self.selections.pending_mode().unwrap();
 3720            match &mode {
 3721                SelectMode::Character => {
 3722                    head = position.to_point(&display_map);
 3723                    tail = pending.tail().to_point(buffer);
 3724                }
 3725                SelectMode::Word(original_range) => {
 3726                    let offset = display_map
 3727                        .clip_point(position, Bias::Left)
 3728                        .to_offset(&display_map, Bias::Left);
 3729                    let original_range = original_range.to_offset(buffer);
 3730
 3731                    let head_offset = if buffer.is_inside_word(offset, None)
 3732                        || original_range.contains(&offset)
 3733                    {
 3734                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3735                        if word_range.start < original_range.start {
 3736                            word_range.start
 3737                        } else {
 3738                            word_range.end
 3739                        }
 3740                    } else {
 3741                        offset
 3742                    };
 3743
 3744                    head = head_offset.to_point(buffer);
 3745                    if head_offset <= original_range.start {
 3746                        tail = original_range.end.to_point(buffer);
 3747                    } else {
 3748                        tail = original_range.start.to_point(buffer);
 3749                    }
 3750                }
 3751                SelectMode::Line(original_range) => {
 3752                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3753
 3754                    let position = display_map
 3755                        .clip_point(position, Bias::Left)
 3756                        .to_point(&display_map);
 3757                    let line_start = display_map.prev_line_boundary(position).0;
 3758                    let next_line_start = buffer.clip_point(
 3759                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3760                        Bias::Left,
 3761                    );
 3762
 3763                    if line_start < original_range.start {
 3764                        head = line_start
 3765                    } else {
 3766                        head = next_line_start
 3767                    }
 3768
 3769                    if head <= original_range.start {
 3770                        tail = original_range.end;
 3771                    } else {
 3772                        tail = original_range.start;
 3773                    }
 3774                }
 3775                SelectMode::All => {
 3776                    return;
 3777                }
 3778            };
 3779
 3780            if head < tail {
 3781                pending.start = buffer.anchor_before(head);
 3782                pending.end = buffer.anchor_before(tail);
 3783                pending.reversed = true;
 3784            } else {
 3785                pending.start = buffer.anchor_before(tail);
 3786                pending.end = buffer.anchor_before(head);
 3787                pending.reversed = false;
 3788            }
 3789
 3790            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3791                s.set_pending(pending.clone(), mode);
 3792            });
 3793        } else {
 3794            log::error!("update_selection dispatched with no pending selection");
 3795            return;
 3796        }
 3797
 3798        self.apply_scroll_delta(scroll_delta, window, cx);
 3799        cx.notify();
 3800    }
 3801
 3802    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3803        self.columnar_selection_state.take();
 3804        if let Some(pending_mode) = self.selections.pending_mode() {
 3805            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3806            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3807                s.select(selections);
 3808                s.clear_pending();
 3809                if s.is_extending() {
 3810                    s.set_is_extending(false);
 3811                } else {
 3812                    s.set_select_mode(pending_mode);
 3813                }
 3814            });
 3815        }
 3816    }
 3817
 3818    fn select_columns(
 3819        &mut self,
 3820        head: DisplayPoint,
 3821        goal_column: u32,
 3822        display_map: &DisplaySnapshot,
 3823        window: &mut Window,
 3824        cx: &mut Context<Self>,
 3825    ) {
 3826        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3827            return;
 3828        };
 3829
 3830        let tail = match columnar_state {
 3831            ColumnarSelectionState::FromMouse {
 3832                selection_tail,
 3833                display_point,
 3834            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3835            ColumnarSelectionState::FromSelection { selection_tail } => {
 3836                selection_tail.to_display_point(display_map)
 3837            }
 3838        };
 3839
 3840        let start_row = cmp::min(tail.row(), head.row());
 3841        let end_row = cmp::max(tail.row(), head.row());
 3842        let start_column = cmp::min(tail.column(), goal_column);
 3843        let end_column = cmp::max(tail.column(), goal_column);
 3844        let reversed = start_column < tail.column();
 3845
 3846        let selection_ranges = (start_row.0..=end_row.0)
 3847            .map(DisplayRow)
 3848            .filter_map(|row| {
 3849                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3850                    || start_column <= display_map.line_len(row))
 3851                    && !display_map.is_block_line(row)
 3852                {
 3853                    let start = display_map
 3854                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3855                        .to_point(display_map);
 3856                    let end = display_map
 3857                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3858                        .to_point(display_map);
 3859                    if reversed {
 3860                        Some(end..start)
 3861                    } else {
 3862                        Some(start..end)
 3863                    }
 3864                } else {
 3865                    None
 3866                }
 3867            })
 3868            .collect::<Vec<_>>();
 3869        if selection_ranges.is_empty() {
 3870            return;
 3871        }
 3872
 3873        let ranges = match columnar_state {
 3874            ColumnarSelectionState::FromMouse { .. } => {
 3875                let mut non_empty_ranges = selection_ranges
 3876                    .iter()
 3877                    .filter(|selection_range| selection_range.start != selection_range.end)
 3878                    .peekable();
 3879                if non_empty_ranges.peek().is_some() {
 3880                    non_empty_ranges.cloned().collect()
 3881                } else {
 3882                    selection_ranges
 3883                }
 3884            }
 3885            _ => selection_ranges,
 3886        };
 3887
 3888        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3889            s.select_ranges(ranges);
 3890        });
 3891        cx.notify();
 3892    }
 3893
 3894    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3895        self.selections
 3896            .all_adjusted(snapshot)
 3897            .iter()
 3898            .any(|selection| !selection.is_empty())
 3899    }
 3900
 3901    pub fn has_pending_nonempty_selection(&self) -> bool {
 3902        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3903            Some(Selection { start, end, .. }) => start != end,
 3904            None => false,
 3905        };
 3906
 3907        pending_nonempty_selection
 3908            || (self.columnar_selection_state.is_some()
 3909                && self.selections.disjoint_anchors().len() > 1)
 3910    }
 3911
 3912    pub fn has_pending_selection(&self) -> bool {
 3913        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3914    }
 3915
 3916    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3917        self.selection_mark_mode = false;
 3918        self.selection_drag_state = SelectionDragState::None;
 3919
 3920        if self.clear_expanded_diff_hunks(cx) {
 3921            cx.notify();
 3922            return;
 3923        }
 3924        if self.dismiss_menus_and_popups(true, window, cx) {
 3925            return;
 3926        }
 3927
 3928        if self.mode.is_full()
 3929            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3930        {
 3931            return;
 3932        }
 3933
 3934        cx.propagate();
 3935    }
 3936
 3937    pub fn dismiss_menus_and_popups(
 3938        &mut self,
 3939        is_user_requested: bool,
 3940        window: &mut Window,
 3941        cx: &mut Context<Self>,
 3942    ) -> bool {
 3943        if self.take_rename(false, window, cx).is_some() {
 3944            return true;
 3945        }
 3946
 3947        if self.hide_blame_popover(true, cx) {
 3948            return true;
 3949        }
 3950
 3951        if hide_hover(self, cx) {
 3952            return true;
 3953        }
 3954
 3955        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3956            return true;
 3957        }
 3958
 3959        if self.hide_context_menu(window, cx).is_some() {
 3960            return true;
 3961        }
 3962
 3963        if self.mouse_context_menu.take().is_some() {
 3964            return true;
 3965        }
 3966
 3967        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3968            return true;
 3969        }
 3970
 3971        if self.snippet_stack.pop().is_some() {
 3972            return true;
 3973        }
 3974
 3975        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3976            self.dismiss_diagnostics(cx);
 3977            return true;
 3978        }
 3979
 3980        false
 3981    }
 3982
 3983    fn linked_editing_ranges_for(
 3984        &self,
 3985        selection: Range<text::Anchor>,
 3986        cx: &App,
 3987    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3988        if self.linked_edit_ranges.is_empty() {
 3989            return None;
 3990        }
 3991        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3992            selection.end.buffer_id.and_then(|end_buffer_id| {
 3993                if selection.start.buffer_id != Some(end_buffer_id) {
 3994                    return None;
 3995                }
 3996                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3997                let snapshot = buffer.read(cx).snapshot();
 3998                self.linked_edit_ranges
 3999                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4000                    .map(|ranges| (ranges, snapshot, buffer))
 4001            })?;
 4002        use text::ToOffset as TO;
 4003        // find offset from the start of current range to current cursor position
 4004        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4005
 4006        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4007        let start_difference = start_offset - start_byte_offset;
 4008        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4009        let end_difference = end_offset - start_byte_offset;
 4010        // Current range has associated linked ranges.
 4011        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4012        for range in linked_ranges.iter() {
 4013            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4014            let end_offset = start_offset + end_difference;
 4015            let start_offset = start_offset + start_difference;
 4016            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4017                continue;
 4018            }
 4019            if self.selections.disjoint_anchor_ranges().any(|s| {
 4020                if s.start.buffer_id != selection.start.buffer_id
 4021                    || s.end.buffer_id != selection.end.buffer_id
 4022                {
 4023                    return false;
 4024                }
 4025                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4026                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4027            }) {
 4028                continue;
 4029            }
 4030            let start = buffer_snapshot.anchor_after(start_offset);
 4031            let end = buffer_snapshot.anchor_after(end_offset);
 4032            linked_edits
 4033                .entry(buffer.clone())
 4034                .or_default()
 4035                .push(start..end);
 4036        }
 4037        Some(linked_edits)
 4038    }
 4039
 4040    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4041        let text: Arc<str> = text.into();
 4042
 4043        if self.read_only(cx) {
 4044            return;
 4045        }
 4046
 4047        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4048
 4049        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4050        let mut bracket_inserted = false;
 4051        let mut edits = Vec::new();
 4052        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4053        let mut new_selections = Vec::with_capacity(selections.len());
 4054        let mut new_autoclose_regions = Vec::new();
 4055        let snapshot = self.buffer.read(cx).read(cx);
 4056        let mut clear_linked_edit_ranges = false;
 4057
 4058        for (selection, autoclose_region) in
 4059            self.selections_with_autoclose_regions(selections, &snapshot)
 4060        {
 4061            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4062                // Determine if the inserted text matches the opening or closing
 4063                // bracket of any of this language's bracket pairs.
 4064                let mut bracket_pair = None;
 4065                let mut is_bracket_pair_start = false;
 4066                let mut is_bracket_pair_end = false;
 4067                if !text.is_empty() {
 4068                    let mut bracket_pair_matching_end = None;
 4069                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4070                    //  and they are removing the character that triggered IME popup.
 4071                    for (pair, enabled) in scope.brackets() {
 4072                        if !pair.close && !pair.surround {
 4073                            continue;
 4074                        }
 4075
 4076                        if enabled && pair.start.ends_with(text.as_ref()) {
 4077                            let prefix_len = pair.start.len() - text.len();
 4078                            let preceding_text_matches_prefix = prefix_len == 0
 4079                                || (selection.start.column >= (prefix_len as u32)
 4080                                    && snapshot.contains_str_at(
 4081                                        Point::new(
 4082                                            selection.start.row,
 4083                                            selection.start.column - (prefix_len as u32),
 4084                                        ),
 4085                                        &pair.start[..prefix_len],
 4086                                    ));
 4087                            if preceding_text_matches_prefix {
 4088                                bracket_pair = Some(pair.clone());
 4089                                is_bracket_pair_start = true;
 4090                                break;
 4091                            }
 4092                        }
 4093                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4094                        {
 4095                            // take first bracket pair matching end, but don't break in case a later bracket
 4096                            // pair matches start
 4097                            bracket_pair_matching_end = Some(pair.clone());
 4098                        }
 4099                    }
 4100                    if let Some(end) = bracket_pair_matching_end
 4101                        && bracket_pair.is_none()
 4102                    {
 4103                        bracket_pair = Some(end);
 4104                        is_bracket_pair_end = true;
 4105                    }
 4106                }
 4107
 4108                if let Some(bracket_pair) = bracket_pair {
 4109                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4110                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4111                    let auto_surround =
 4112                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4113                    if selection.is_empty() {
 4114                        if is_bracket_pair_start {
 4115                            // If the inserted text is a suffix of an opening bracket and the
 4116                            // selection is preceded by the rest of the opening bracket, then
 4117                            // insert the closing bracket.
 4118                            let following_text_allows_autoclose = snapshot
 4119                                .chars_at(selection.start)
 4120                                .next()
 4121                                .is_none_or(|c| scope.should_autoclose_before(c));
 4122
 4123                            let preceding_text_allows_autoclose = selection.start.column == 0
 4124                                || snapshot
 4125                                    .reversed_chars_at(selection.start)
 4126                                    .next()
 4127                                    .is_none_or(|c| {
 4128                                        bracket_pair.start != bracket_pair.end
 4129                                            || !snapshot
 4130                                                .char_classifier_at(selection.start)
 4131                                                .is_word(c)
 4132                                    });
 4133
 4134                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4135                                && bracket_pair.start.len() == 1
 4136                            {
 4137                                let target = bracket_pair.start.chars().next().unwrap();
 4138                                let current_line_count = snapshot
 4139                                    .reversed_chars_at(selection.start)
 4140                                    .take_while(|&c| c != '\n')
 4141                                    .filter(|&c| c == target)
 4142                                    .count();
 4143                                current_line_count % 2 == 1
 4144                            } else {
 4145                                false
 4146                            };
 4147
 4148                            if autoclose
 4149                                && bracket_pair.close
 4150                                && following_text_allows_autoclose
 4151                                && preceding_text_allows_autoclose
 4152                                && !is_closing_quote
 4153                            {
 4154                                let anchor = snapshot.anchor_before(selection.end);
 4155                                new_selections.push((selection.map(|_| anchor), text.len()));
 4156                                new_autoclose_regions.push((
 4157                                    anchor,
 4158                                    text.len(),
 4159                                    selection.id,
 4160                                    bracket_pair.clone(),
 4161                                ));
 4162                                edits.push((
 4163                                    selection.range(),
 4164                                    format!("{}{}", text, bracket_pair.end).into(),
 4165                                ));
 4166                                bracket_inserted = true;
 4167                                continue;
 4168                            }
 4169                        }
 4170
 4171                        if let Some(region) = autoclose_region {
 4172                            // If the selection is followed by an auto-inserted closing bracket,
 4173                            // then don't insert that closing bracket again; just move the selection
 4174                            // past the closing bracket.
 4175                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4176                                && text.as_ref() == region.pair.end.as_str()
 4177                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4178                            if should_skip {
 4179                                let anchor = snapshot.anchor_after(selection.end);
 4180                                new_selections
 4181                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4182                                continue;
 4183                            }
 4184                        }
 4185
 4186                        let always_treat_brackets_as_autoclosed = snapshot
 4187                            .language_settings_at(selection.start, cx)
 4188                            .always_treat_brackets_as_autoclosed;
 4189                        if always_treat_brackets_as_autoclosed
 4190                            && is_bracket_pair_end
 4191                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4192                        {
 4193                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4194                            // and the inserted text is a closing bracket and the selection is followed
 4195                            // by the closing bracket then move the selection past the closing bracket.
 4196                            let anchor = snapshot.anchor_after(selection.end);
 4197                            new_selections.push((selection.map(|_| anchor), text.len()));
 4198                            continue;
 4199                        }
 4200                    }
 4201                    // If an opening bracket is 1 character long and is typed while
 4202                    // text is selected, then surround that text with the bracket pair.
 4203                    else if auto_surround
 4204                        && bracket_pair.surround
 4205                        && is_bracket_pair_start
 4206                        && bracket_pair.start.chars().count() == 1
 4207                    {
 4208                        edits.push((selection.start..selection.start, text.clone()));
 4209                        edits.push((
 4210                            selection.end..selection.end,
 4211                            bracket_pair.end.as_str().into(),
 4212                        ));
 4213                        bracket_inserted = true;
 4214                        new_selections.push((
 4215                            Selection {
 4216                                id: selection.id,
 4217                                start: snapshot.anchor_after(selection.start),
 4218                                end: snapshot.anchor_before(selection.end),
 4219                                reversed: selection.reversed,
 4220                                goal: selection.goal,
 4221                            },
 4222                            0,
 4223                        ));
 4224                        continue;
 4225                    }
 4226                }
 4227            }
 4228
 4229            if self.auto_replace_emoji_shortcode
 4230                && selection.is_empty()
 4231                && text.as_ref().ends_with(':')
 4232                && let Some(possible_emoji_short_code) =
 4233                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4234                && !possible_emoji_short_code.is_empty()
 4235                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4236            {
 4237                let emoji_shortcode_start = Point::new(
 4238                    selection.start.row,
 4239                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4240                );
 4241
 4242                // Remove shortcode from buffer
 4243                edits.push((
 4244                    emoji_shortcode_start..selection.start,
 4245                    "".to_string().into(),
 4246                ));
 4247                new_selections.push((
 4248                    Selection {
 4249                        id: selection.id,
 4250                        start: snapshot.anchor_after(emoji_shortcode_start),
 4251                        end: snapshot.anchor_before(selection.start),
 4252                        reversed: selection.reversed,
 4253                        goal: selection.goal,
 4254                    },
 4255                    0,
 4256                ));
 4257
 4258                // Insert emoji
 4259                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4260                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4261                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4262
 4263                continue;
 4264            }
 4265
 4266            // If not handling any auto-close operation, then just replace the selected
 4267            // text with the given input and move the selection to the end of the
 4268            // newly inserted text.
 4269            let anchor = snapshot.anchor_after(selection.end);
 4270            if !self.linked_edit_ranges.is_empty() {
 4271                let start_anchor = snapshot.anchor_before(selection.start);
 4272
 4273                let is_word_char = text.chars().next().is_none_or(|char| {
 4274                    let classifier = snapshot
 4275                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4276                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4277                    classifier.is_word(char)
 4278                });
 4279
 4280                if is_word_char {
 4281                    if let Some(ranges) = self
 4282                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4283                    {
 4284                        for (buffer, edits) in ranges {
 4285                            linked_edits
 4286                                .entry(buffer.clone())
 4287                                .or_default()
 4288                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4289                        }
 4290                    }
 4291                } else {
 4292                    clear_linked_edit_ranges = true;
 4293                }
 4294            }
 4295
 4296            new_selections.push((selection.map(|_| anchor), 0));
 4297            edits.push((selection.start..selection.end, text.clone()));
 4298        }
 4299
 4300        drop(snapshot);
 4301
 4302        self.transact(window, cx, |this, window, cx| {
 4303            if clear_linked_edit_ranges {
 4304                this.linked_edit_ranges.clear();
 4305            }
 4306            let initial_buffer_versions =
 4307                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4308
 4309            this.buffer.update(cx, |buffer, cx| {
 4310                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4311            });
 4312            for (buffer, edits) in linked_edits {
 4313                buffer.update(cx, |buffer, cx| {
 4314                    let snapshot = buffer.snapshot();
 4315                    let edits = edits
 4316                        .into_iter()
 4317                        .map(|(range, text)| {
 4318                            use text::ToPoint as TP;
 4319                            let end_point = TP::to_point(&range.end, &snapshot);
 4320                            let start_point = TP::to_point(&range.start, &snapshot);
 4321                            (start_point..end_point, text)
 4322                        })
 4323                        .sorted_by_key(|(range, _)| range.start);
 4324                    buffer.edit(edits, None, cx);
 4325                })
 4326            }
 4327            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4328            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4329            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4330            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4331                .zip(new_selection_deltas)
 4332                .map(|(selection, delta)| Selection {
 4333                    id: selection.id,
 4334                    start: selection.start + delta,
 4335                    end: selection.end + delta,
 4336                    reversed: selection.reversed,
 4337                    goal: SelectionGoal::None,
 4338                })
 4339                .collect::<Vec<_>>();
 4340
 4341            let mut i = 0;
 4342            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4343                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4344                let start = map.buffer_snapshot().anchor_before(position);
 4345                let end = map.buffer_snapshot().anchor_after(position);
 4346                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4347                    match existing_state
 4348                        .range
 4349                        .start
 4350                        .cmp(&start, map.buffer_snapshot())
 4351                    {
 4352                        Ordering::Less => i += 1,
 4353                        Ordering::Greater => break,
 4354                        Ordering::Equal => {
 4355                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4356                                Ordering::Less => i += 1,
 4357                                Ordering::Equal => break,
 4358                                Ordering::Greater => break,
 4359                            }
 4360                        }
 4361                    }
 4362                }
 4363                this.autoclose_regions.insert(
 4364                    i,
 4365                    AutocloseRegion {
 4366                        selection_id,
 4367                        range: start..end,
 4368                        pair,
 4369                    },
 4370                );
 4371            }
 4372
 4373            let had_active_edit_prediction = this.has_active_edit_prediction();
 4374            this.change_selections(
 4375                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4376                window,
 4377                cx,
 4378                |s| s.select(new_selections),
 4379            );
 4380
 4381            if !bracket_inserted
 4382                && let Some(on_type_format_task) =
 4383                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4384            {
 4385                on_type_format_task.detach_and_log_err(cx);
 4386            }
 4387
 4388            let editor_settings = EditorSettings::get_global(cx);
 4389            if bracket_inserted
 4390                && (editor_settings.auto_signature_help
 4391                    || editor_settings.show_signature_help_after_edits)
 4392            {
 4393                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4394            }
 4395
 4396            let trigger_in_words =
 4397                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4398            if this.hard_wrap.is_some() {
 4399                let latest: Range<Point> = this.selections.newest(&map).range();
 4400                if latest.is_empty()
 4401                    && this
 4402                        .buffer()
 4403                        .read(cx)
 4404                        .snapshot(cx)
 4405                        .line_len(MultiBufferRow(latest.start.row))
 4406                        == latest.start.column
 4407                {
 4408                    this.rewrap_impl(
 4409                        RewrapOptions {
 4410                            override_language_settings: true,
 4411                            preserve_existing_whitespace: true,
 4412                        },
 4413                        cx,
 4414                    )
 4415                }
 4416            }
 4417            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4418            refresh_linked_ranges(this, window, cx);
 4419            this.refresh_edit_prediction(true, false, window, cx);
 4420            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4421        });
 4422    }
 4423
 4424    fn find_possible_emoji_shortcode_at_position(
 4425        snapshot: &MultiBufferSnapshot,
 4426        position: Point,
 4427    ) -> Option<String> {
 4428        let mut chars = Vec::new();
 4429        let mut found_colon = false;
 4430        for char in snapshot.reversed_chars_at(position).take(100) {
 4431            // Found a possible emoji shortcode in the middle of the buffer
 4432            if found_colon {
 4433                if char.is_whitespace() {
 4434                    chars.reverse();
 4435                    return Some(chars.iter().collect());
 4436                }
 4437                // If the previous character is not a whitespace, we are in the middle of a word
 4438                // and we only want to complete the shortcode if the word is made up of other emojis
 4439                let mut containing_word = String::new();
 4440                for ch in snapshot
 4441                    .reversed_chars_at(position)
 4442                    .skip(chars.len() + 1)
 4443                    .take(100)
 4444                {
 4445                    if ch.is_whitespace() {
 4446                        break;
 4447                    }
 4448                    containing_word.push(ch);
 4449                }
 4450                let containing_word = containing_word.chars().rev().collect::<String>();
 4451                if util::word_consists_of_emojis(containing_word.as_str()) {
 4452                    chars.reverse();
 4453                    return Some(chars.iter().collect());
 4454                }
 4455            }
 4456
 4457            if char.is_whitespace() || !char.is_ascii() {
 4458                return None;
 4459            }
 4460            if char == ':' {
 4461                found_colon = true;
 4462            } else {
 4463                chars.push(char);
 4464            }
 4465        }
 4466        // Found a possible emoji shortcode at the beginning of the buffer
 4467        chars.reverse();
 4468        Some(chars.iter().collect())
 4469    }
 4470
 4471    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4472        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4473        self.transact(window, cx, |this, window, cx| {
 4474            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4475                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4476                let multi_buffer = this.buffer.read(cx);
 4477                let buffer = multi_buffer.snapshot(cx);
 4478                selections
 4479                    .iter()
 4480                    .map(|selection| {
 4481                        let start_point = selection.start.to_point(&buffer);
 4482                        let mut existing_indent =
 4483                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4484                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4485                        let start = selection.start;
 4486                        let end = selection.end;
 4487                        let selection_is_empty = start == end;
 4488                        let language_scope = buffer.language_scope_at(start);
 4489                        let (
 4490                            comment_delimiter,
 4491                            doc_delimiter,
 4492                            insert_extra_newline,
 4493                            indent_on_newline,
 4494                            indent_on_extra_newline,
 4495                        ) = if let Some(language) = &language_scope {
 4496                            let mut insert_extra_newline =
 4497                                insert_extra_newline_brackets(&buffer, start..end, language)
 4498                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4499
 4500                            // Comment extension on newline is allowed only for cursor selections
 4501                            let comment_delimiter = maybe!({
 4502                                if !selection_is_empty {
 4503                                    return None;
 4504                                }
 4505
 4506                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4507                                    return None;
 4508                                }
 4509
 4510                                let delimiters = language.line_comment_prefixes();
 4511                                let max_len_of_delimiter =
 4512                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4513                                let (snapshot, range) =
 4514                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4515
 4516                                let num_of_whitespaces = snapshot
 4517                                    .chars_for_range(range.clone())
 4518                                    .take_while(|c| c.is_whitespace())
 4519                                    .count();
 4520                                let comment_candidate = snapshot
 4521                                    .chars_for_range(range.clone())
 4522                                    .skip(num_of_whitespaces)
 4523                                    .take(max_len_of_delimiter)
 4524                                    .collect::<String>();
 4525                                let (delimiter, trimmed_len) = delimiters
 4526                                    .iter()
 4527                                    .filter_map(|delimiter| {
 4528                                        let prefix = delimiter.trim_end();
 4529                                        if comment_candidate.starts_with(prefix) {
 4530                                            Some((delimiter, prefix.len()))
 4531                                        } else {
 4532                                            None
 4533                                        }
 4534                                    })
 4535                                    .max_by_key(|(_, len)| *len)?;
 4536
 4537                                if let Some(BlockCommentConfig {
 4538                                    start: block_start, ..
 4539                                }) = language.block_comment()
 4540                                {
 4541                                    let block_start_trimmed = block_start.trim_end();
 4542                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4543                                        let line_content = snapshot
 4544                                            .chars_for_range(range)
 4545                                            .skip(num_of_whitespaces)
 4546                                            .take(block_start_trimmed.len())
 4547                                            .collect::<String>();
 4548
 4549                                        if line_content.starts_with(block_start_trimmed) {
 4550                                            return None;
 4551                                        }
 4552                                    }
 4553                                }
 4554
 4555                                let cursor_is_placed_after_comment_marker =
 4556                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4557                                if cursor_is_placed_after_comment_marker {
 4558                                    Some(delimiter.clone())
 4559                                } else {
 4560                                    None
 4561                                }
 4562                            });
 4563
 4564                            let mut indent_on_newline = IndentSize::spaces(0);
 4565                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4566
 4567                            let doc_delimiter = maybe!({
 4568                                if !selection_is_empty {
 4569                                    return None;
 4570                                }
 4571
 4572                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4573                                    return None;
 4574                                }
 4575
 4576                                let BlockCommentConfig {
 4577                                    start: start_tag,
 4578                                    end: end_tag,
 4579                                    prefix: delimiter,
 4580                                    tab_size: len,
 4581                                } = language.documentation_comment()?;
 4582                                let is_within_block_comment = buffer
 4583                                    .language_scope_at(start_point)
 4584                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4585                                if !is_within_block_comment {
 4586                                    return None;
 4587                                }
 4588
 4589                                let (snapshot, range) =
 4590                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4591
 4592                                let num_of_whitespaces = snapshot
 4593                                    .chars_for_range(range.clone())
 4594                                    .take_while(|c| c.is_whitespace())
 4595                                    .count();
 4596
 4597                                // 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.
 4598                                let column = start_point.column;
 4599                                let cursor_is_after_start_tag = {
 4600                                    let start_tag_len = start_tag.len();
 4601                                    let start_tag_line = snapshot
 4602                                        .chars_for_range(range.clone())
 4603                                        .skip(num_of_whitespaces)
 4604                                        .take(start_tag_len)
 4605                                        .collect::<String>();
 4606                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4607                                        num_of_whitespaces + start_tag_len <= column as usize
 4608                                    } else {
 4609                                        false
 4610                                    }
 4611                                };
 4612
 4613                                let cursor_is_after_delimiter = {
 4614                                    let delimiter_trim = delimiter.trim_end();
 4615                                    let delimiter_line = snapshot
 4616                                        .chars_for_range(range.clone())
 4617                                        .skip(num_of_whitespaces)
 4618                                        .take(delimiter_trim.len())
 4619                                        .collect::<String>();
 4620                                    if delimiter_line.starts_with(delimiter_trim) {
 4621                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4622                                    } else {
 4623                                        false
 4624                                    }
 4625                                };
 4626
 4627                                let cursor_is_before_end_tag_if_exists = {
 4628                                    let mut char_position = 0u32;
 4629                                    let mut end_tag_offset = None;
 4630
 4631                                    'outer: for chunk in snapshot.text_for_range(range) {
 4632                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4633                                            let chars_before_match =
 4634                                                chunk[..byte_pos].chars().count() as u32;
 4635                                            end_tag_offset =
 4636                                                Some(char_position + chars_before_match);
 4637                                            break 'outer;
 4638                                        }
 4639                                        char_position += chunk.chars().count() as u32;
 4640                                    }
 4641
 4642                                    if let Some(end_tag_offset) = end_tag_offset {
 4643                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4644                                        if cursor_is_after_start_tag {
 4645                                            if cursor_is_before_end_tag {
 4646                                                insert_extra_newline = true;
 4647                                            }
 4648                                            let cursor_is_at_start_of_end_tag =
 4649                                                column == end_tag_offset;
 4650                                            if cursor_is_at_start_of_end_tag {
 4651                                                indent_on_extra_newline.len = *len;
 4652                                            }
 4653                                        }
 4654                                        cursor_is_before_end_tag
 4655                                    } else {
 4656                                        true
 4657                                    }
 4658                                };
 4659
 4660                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4661                                    && cursor_is_before_end_tag_if_exists
 4662                                {
 4663                                    if cursor_is_after_start_tag {
 4664                                        indent_on_newline.len = *len;
 4665                                    }
 4666                                    Some(delimiter.clone())
 4667                                } else {
 4668                                    None
 4669                                }
 4670                            });
 4671
 4672                            (
 4673                                comment_delimiter,
 4674                                doc_delimiter,
 4675                                insert_extra_newline,
 4676                                indent_on_newline,
 4677                                indent_on_extra_newline,
 4678                            )
 4679                        } else {
 4680                            (
 4681                                None,
 4682                                None,
 4683                                false,
 4684                                IndentSize::default(),
 4685                                IndentSize::default(),
 4686                            )
 4687                        };
 4688
 4689                        let prevent_auto_indent = doc_delimiter.is_some();
 4690                        let delimiter = comment_delimiter.or(doc_delimiter);
 4691
 4692                        let capacity_for_delimiter =
 4693                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4694                        let mut new_text = String::with_capacity(
 4695                            1 + capacity_for_delimiter
 4696                                + existing_indent.len as usize
 4697                                + indent_on_newline.len as usize
 4698                                + indent_on_extra_newline.len as usize,
 4699                        );
 4700                        new_text.push('\n');
 4701                        new_text.extend(existing_indent.chars());
 4702                        new_text.extend(indent_on_newline.chars());
 4703
 4704                        if let Some(delimiter) = &delimiter {
 4705                            new_text.push_str(delimiter);
 4706                        }
 4707
 4708                        if insert_extra_newline {
 4709                            new_text.push('\n');
 4710                            new_text.extend(existing_indent.chars());
 4711                            new_text.extend(indent_on_extra_newline.chars());
 4712                        }
 4713
 4714                        let anchor = buffer.anchor_after(end);
 4715                        let new_selection = selection.map(|_| anchor);
 4716                        (
 4717                            ((start..end, new_text), prevent_auto_indent),
 4718                            (insert_extra_newline, new_selection),
 4719                        )
 4720                    })
 4721                    .unzip()
 4722            };
 4723
 4724            let mut auto_indent_edits = Vec::new();
 4725            let mut edits = Vec::new();
 4726            for (edit, prevent_auto_indent) in edits_with_flags {
 4727                if prevent_auto_indent {
 4728                    edits.push(edit);
 4729                } else {
 4730                    auto_indent_edits.push(edit);
 4731                }
 4732            }
 4733            if !edits.is_empty() {
 4734                this.edit(edits, cx);
 4735            }
 4736            if !auto_indent_edits.is_empty() {
 4737                this.edit_with_autoindent(auto_indent_edits, cx);
 4738            }
 4739
 4740            let buffer = this.buffer.read(cx).snapshot(cx);
 4741            let new_selections = selection_info
 4742                .into_iter()
 4743                .map(|(extra_newline_inserted, new_selection)| {
 4744                    let mut cursor = new_selection.end.to_point(&buffer);
 4745                    if extra_newline_inserted {
 4746                        cursor.row -= 1;
 4747                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4748                    }
 4749                    new_selection.map(|_| cursor)
 4750                })
 4751                .collect();
 4752
 4753            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4754            this.refresh_edit_prediction(true, false, window, cx);
 4755        });
 4756    }
 4757
 4758    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4759        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4760
 4761        let buffer = self.buffer.read(cx);
 4762        let snapshot = buffer.snapshot(cx);
 4763
 4764        let mut edits = Vec::new();
 4765        let mut rows = Vec::new();
 4766
 4767        for (rows_inserted, selection) in self
 4768            .selections
 4769            .all_adjusted(&self.display_snapshot(cx))
 4770            .into_iter()
 4771            .enumerate()
 4772        {
 4773            let cursor = selection.head();
 4774            let row = cursor.row;
 4775
 4776            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4777
 4778            let newline = "\n".to_string();
 4779            edits.push((start_of_line..start_of_line, newline));
 4780
 4781            rows.push(row + rows_inserted as u32);
 4782        }
 4783
 4784        self.transact(window, cx, |editor, window, cx| {
 4785            editor.edit(edits, cx);
 4786
 4787            editor.change_selections(Default::default(), window, cx, |s| {
 4788                let mut index = 0;
 4789                s.move_cursors_with(|map, _, _| {
 4790                    let row = rows[index];
 4791                    index += 1;
 4792
 4793                    let point = Point::new(row, 0);
 4794                    let boundary = map.next_line_boundary(point).1;
 4795                    let clipped = map.clip_point(boundary, Bias::Left);
 4796
 4797                    (clipped, SelectionGoal::None)
 4798                });
 4799            });
 4800
 4801            let mut indent_edits = Vec::new();
 4802            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4803            for row in rows {
 4804                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4805                for (row, indent) in indents {
 4806                    if indent.len == 0 {
 4807                        continue;
 4808                    }
 4809
 4810                    let text = match indent.kind {
 4811                        IndentKind::Space => " ".repeat(indent.len as usize),
 4812                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4813                    };
 4814                    let point = Point::new(row.0, 0);
 4815                    indent_edits.push((point..point, text));
 4816                }
 4817            }
 4818            editor.edit(indent_edits, cx);
 4819        });
 4820    }
 4821
 4822    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4823        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4824
 4825        let buffer = self.buffer.read(cx);
 4826        let snapshot = buffer.snapshot(cx);
 4827
 4828        let mut edits = Vec::new();
 4829        let mut rows = Vec::new();
 4830        let mut rows_inserted = 0;
 4831
 4832        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4833            let cursor = selection.head();
 4834            let row = cursor.row;
 4835
 4836            let point = Point::new(row + 1, 0);
 4837            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4838
 4839            let newline = "\n".to_string();
 4840            edits.push((start_of_line..start_of_line, newline));
 4841
 4842            rows_inserted += 1;
 4843            rows.push(row + rows_inserted);
 4844        }
 4845
 4846        self.transact(window, cx, |editor, window, cx| {
 4847            editor.edit(edits, cx);
 4848
 4849            editor.change_selections(Default::default(), window, cx, |s| {
 4850                let mut index = 0;
 4851                s.move_cursors_with(|map, _, _| {
 4852                    let row = rows[index];
 4853                    index += 1;
 4854
 4855                    let point = Point::new(row, 0);
 4856                    let boundary = map.next_line_boundary(point).1;
 4857                    let clipped = map.clip_point(boundary, Bias::Left);
 4858
 4859                    (clipped, SelectionGoal::None)
 4860                });
 4861            });
 4862
 4863            let mut indent_edits = Vec::new();
 4864            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4865            for row in rows {
 4866                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4867                for (row, indent) in indents {
 4868                    if indent.len == 0 {
 4869                        continue;
 4870                    }
 4871
 4872                    let text = match indent.kind {
 4873                        IndentKind::Space => " ".repeat(indent.len as usize),
 4874                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4875                    };
 4876                    let point = Point::new(row.0, 0);
 4877                    indent_edits.push((point..point, text));
 4878                }
 4879            }
 4880            editor.edit(indent_edits, cx);
 4881        });
 4882    }
 4883
 4884    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4885        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4886            original_indent_columns: Vec::new(),
 4887        });
 4888        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4889    }
 4890
 4891    fn insert_with_autoindent_mode(
 4892        &mut self,
 4893        text: &str,
 4894        autoindent_mode: Option<AutoindentMode>,
 4895        window: &mut Window,
 4896        cx: &mut Context<Self>,
 4897    ) {
 4898        if self.read_only(cx) {
 4899            return;
 4900        }
 4901
 4902        let text: Arc<str> = text.into();
 4903        self.transact(window, cx, |this, window, cx| {
 4904            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 4905            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4906                let anchors = {
 4907                    let snapshot = buffer.read(cx);
 4908                    old_selections
 4909                        .iter()
 4910                        .map(|s| {
 4911                            let anchor = snapshot.anchor_after(s.head());
 4912                            s.map(|_| anchor)
 4913                        })
 4914                        .collect::<Vec<_>>()
 4915                };
 4916                buffer.edit(
 4917                    old_selections
 4918                        .iter()
 4919                        .map(|s| (s.start..s.end, text.clone())),
 4920                    autoindent_mode,
 4921                    cx,
 4922                );
 4923                anchors
 4924            });
 4925
 4926            this.change_selections(Default::default(), window, cx, |s| {
 4927                s.select_anchors(selection_anchors);
 4928            });
 4929
 4930            cx.notify();
 4931        });
 4932    }
 4933
 4934    fn trigger_completion_on_input(
 4935        &mut self,
 4936        text: &str,
 4937        trigger_in_words: bool,
 4938        window: &mut Window,
 4939        cx: &mut Context<Self>,
 4940    ) {
 4941        let completions_source = self
 4942            .context_menu
 4943            .borrow()
 4944            .as_ref()
 4945            .and_then(|menu| match menu {
 4946                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4947                CodeContextMenu::CodeActions(_) => None,
 4948            });
 4949
 4950        match completions_source {
 4951            Some(CompletionsMenuSource::Words { .. }) => {
 4952                self.open_or_update_completions_menu(
 4953                    Some(CompletionsMenuSource::Words {
 4954                        ignore_threshold: false,
 4955                    }),
 4956                    None,
 4957                    window,
 4958                    cx,
 4959                );
 4960            }
 4961            Some(CompletionsMenuSource::Normal)
 4962            | Some(CompletionsMenuSource::SnippetChoices)
 4963            | None
 4964                if self.is_completion_trigger(
 4965                    text,
 4966                    trigger_in_words,
 4967                    completions_source.is_some(),
 4968                    cx,
 4969                ) =>
 4970            {
 4971                self.show_completions(
 4972                    &ShowCompletions {
 4973                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4974                    },
 4975                    window,
 4976                    cx,
 4977                )
 4978            }
 4979            _ => {
 4980                self.hide_context_menu(window, cx);
 4981            }
 4982        }
 4983    }
 4984
 4985    fn is_completion_trigger(
 4986        &self,
 4987        text: &str,
 4988        trigger_in_words: bool,
 4989        menu_is_open: bool,
 4990        cx: &mut Context<Self>,
 4991    ) -> bool {
 4992        let position = self.selections.newest_anchor().head();
 4993        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4994            return false;
 4995        };
 4996
 4997        if let Some(completion_provider) = &self.completion_provider {
 4998            completion_provider.is_completion_trigger(
 4999                &buffer,
 5000                position.text_anchor,
 5001                text,
 5002                trigger_in_words,
 5003                menu_is_open,
 5004                cx,
 5005            )
 5006        } else {
 5007            false
 5008        }
 5009    }
 5010
 5011    /// If any empty selections is touching the start of its innermost containing autoclose
 5012    /// region, expand it to select the brackets.
 5013    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5014        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5015        let buffer = self.buffer.read(cx).read(cx);
 5016        let new_selections = self
 5017            .selections_with_autoclose_regions(selections, &buffer)
 5018            .map(|(mut selection, region)| {
 5019                if !selection.is_empty() {
 5020                    return selection;
 5021                }
 5022
 5023                if let Some(region) = region {
 5024                    let mut range = region.range.to_offset(&buffer);
 5025                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5026                        range.start -= region.pair.start.len();
 5027                        if buffer.contains_str_at(range.start, &region.pair.start)
 5028                            && buffer.contains_str_at(range.end, &region.pair.end)
 5029                        {
 5030                            range.end += region.pair.end.len();
 5031                            selection.start = range.start;
 5032                            selection.end = range.end;
 5033
 5034                            return selection;
 5035                        }
 5036                    }
 5037                }
 5038
 5039                let always_treat_brackets_as_autoclosed = buffer
 5040                    .language_settings_at(selection.start, cx)
 5041                    .always_treat_brackets_as_autoclosed;
 5042
 5043                if !always_treat_brackets_as_autoclosed {
 5044                    return selection;
 5045                }
 5046
 5047                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5048                    for (pair, enabled) in scope.brackets() {
 5049                        if !enabled || !pair.close {
 5050                            continue;
 5051                        }
 5052
 5053                        if buffer.contains_str_at(selection.start, &pair.end) {
 5054                            let pair_start_len = pair.start.len();
 5055                            if buffer.contains_str_at(
 5056                                selection.start.saturating_sub(pair_start_len),
 5057                                &pair.start,
 5058                            ) {
 5059                                selection.start -= pair_start_len;
 5060                                selection.end += pair.end.len();
 5061
 5062                                return selection;
 5063                            }
 5064                        }
 5065                    }
 5066                }
 5067
 5068                selection
 5069            })
 5070            .collect();
 5071
 5072        drop(buffer);
 5073        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5074            selections.select(new_selections)
 5075        });
 5076    }
 5077
 5078    /// Iterate the given selections, and for each one, find the smallest surrounding
 5079    /// autoclose region. This uses the ordering of the selections and the autoclose
 5080    /// regions to avoid repeated comparisons.
 5081    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5082        &'a self,
 5083        selections: impl IntoIterator<Item = Selection<D>>,
 5084        buffer: &'a MultiBufferSnapshot,
 5085    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5086        let mut i = 0;
 5087        let mut regions = self.autoclose_regions.as_slice();
 5088        selections.into_iter().map(move |selection| {
 5089            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5090
 5091            let mut enclosing = None;
 5092            while let Some(pair_state) = regions.get(i) {
 5093                if pair_state.range.end.to_offset(buffer) < range.start {
 5094                    regions = &regions[i + 1..];
 5095                    i = 0;
 5096                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5097                    break;
 5098                } else {
 5099                    if pair_state.selection_id == selection.id {
 5100                        enclosing = Some(pair_state);
 5101                    }
 5102                    i += 1;
 5103                }
 5104            }
 5105
 5106            (selection, enclosing)
 5107        })
 5108    }
 5109
 5110    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5111    fn invalidate_autoclose_regions(
 5112        &mut self,
 5113        mut selections: &[Selection<Anchor>],
 5114        buffer: &MultiBufferSnapshot,
 5115    ) {
 5116        self.autoclose_regions.retain(|state| {
 5117            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5118                return false;
 5119            }
 5120
 5121            let mut i = 0;
 5122            while let Some(selection) = selections.get(i) {
 5123                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5124                    selections = &selections[1..];
 5125                    continue;
 5126                }
 5127                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5128                    break;
 5129                }
 5130                if selection.id == state.selection_id {
 5131                    return true;
 5132                } else {
 5133                    i += 1;
 5134                }
 5135            }
 5136            false
 5137        });
 5138    }
 5139
 5140    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5141        let offset = position.to_offset(buffer);
 5142        let (word_range, kind) =
 5143            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5144        if offset > word_range.start && kind == Some(CharKind::Word) {
 5145            Some(
 5146                buffer
 5147                    .text_for_range(word_range.start..offset)
 5148                    .collect::<String>(),
 5149            )
 5150        } else {
 5151            None
 5152        }
 5153    }
 5154
 5155    pub fn visible_excerpts(
 5156        &self,
 5157        cx: &mut Context<Editor>,
 5158    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5159        let Some(project) = self.project() else {
 5160            return HashMap::default();
 5161        };
 5162        let project = project.read(cx);
 5163        let multi_buffer = self.buffer().read(cx);
 5164        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5165        let multi_buffer_visible_start = self
 5166            .scroll_manager
 5167            .anchor()
 5168            .anchor
 5169            .to_point(&multi_buffer_snapshot);
 5170        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5171            multi_buffer_visible_start
 5172                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5173            Bias::Left,
 5174        );
 5175        multi_buffer_snapshot
 5176            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5177            .into_iter()
 5178            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5179            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5180                let buffer_file = project::File::from_dyn(buffer.file())?;
 5181                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5182                let worktree_entry = buffer_worktree
 5183                    .read(cx)
 5184                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5185                if worktree_entry.is_ignored {
 5186                    None
 5187                } else {
 5188                    Some((
 5189                        excerpt_id,
 5190                        (
 5191                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5192                            buffer.version().clone(),
 5193                            excerpt_visible_range,
 5194                        ),
 5195                    ))
 5196                }
 5197            })
 5198            .collect()
 5199    }
 5200
 5201    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5202        TextLayoutDetails {
 5203            text_system: window.text_system().clone(),
 5204            editor_style: self.style.clone().unwrap(),
 5205            rem_size: window.rem_size(),
 5206            scroll_anchor: self.scroll_manager.anchor(),
 5207            visible_rows: self.visible_line_count(),
 5208            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5209        }
 5210    }
 5211
 5212    fn trigger_on_type_formatting(
 5213        &self,
 5214        input: String,
 5215        window: &mut Window,
 5216        cx: &mut Context<Self>,
 5217    ) -> Option<Task<Result<()>>> {
 5218        if input.len() != 1 {
 5219            return None;
 5220        }
 5221
 5222        let project = self.project()?;
 5223        let position = self.selections.newest_anchor().head();
 5224        let (buffer, buffer_position) = self
 5225            .buffer
 5226            .read(cx)
 5227            .text_anchor_for_position(position, cx)?;
 5228
 5229        let settings = language_settings::language_settings(
 5230            buffer
 5231                .read(cx)
 5232                .language_at(buffer_position)
 5233                .map(|l| l.name()),
 5234            buffer.read(cx).file(),
 5235            cx,
 5236        );
 5237        if !settings.use_on_type_format {
 5238            return None;
 5239        }
 5240
 5241        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5242        // hence we do LSP request & edit on host side only — add formats to host's history.
 5243        let push_to_lsp_host_history = true;
 5244        // If this is not the host, append its history with new edits.
 5245        let push_to_client_history = project.read(cx).is_via_collab();
 5246
 5247        let on_type_formatting = project.update(cx, |project, cx| {
 5248            project.on_type_format(
 5249                buffer.clone(),
 5250                buffer_position,
 5251                input,
 5252                push_to_lsp_host_history,
 5253                cx,
 5254            )
 5255        });
 5256        Some(cx.spawn_in(window, async move |editor, cx| {
 5257            if let Some(transaction) = on_type_formatting.await? {
 5258                if push_to_client_history {
 5259                    buffer
 5260                        .update(cx, |buffer, _| {
 5261                            buffer.push_transaction(transaction, Instant::now());
 5262                            buffer.finalize_last_transaction();
 5263                        })
 5264                        .ok();
 5265                }
 5266                editor.update(cx, |editor, cx| {
 5267                    editor.refresh_document_highlights(cx);
 5268                })?;
 5269            }
 5270            Ok(())
 5271        }))
 5272    }
 5273
 5274    pub fn show_word_completions(
 5275        &mut self,
 5276        _: &ShowWordCompletions,
 5277        window: &mut Window,
 5278        cx: &mut Context<Self>,
 5279    ) {
 5280        self.open_or_update_completions_menu(
 5281            Some(CompletionsMenuSource::Words {
 5282                ignore_threshold: true,
 5283            }),
 5284            None,
 5285            window,
 5286            cx,
 5287        );
 5288    }
 5289
 5290    pub fn show_completions(
 5291        &mut self,
 5292        options: &ShowCompletions,
 5293        window: &mut Window,
 5294        cx: &mut Context<Self>,
 5295    ) {
 5296        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5297    }
 5298
 5299    fn open_or_update_completions_menu(
 5300        &mut self,
 5301        requested_source: Option<CompletionsMenuSource>,
 5302        trigger: Option<&str>,
 5303        window: &mut Window,
 5304        cx: &mut Context<Self>,
 5305    ) {
 5306        if self.pending_rename.is_some() {
 5307            return;
 5308        }
 5309
 5310        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5311
 5312        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5313        // inserted and selected. To handle that case, the start of the selection is used so that
 5314        // the menu starts with all choices.
 5315        let position = self
 5316            .selections
 5317            .newest_anchor()
 5318            .start
 5319            .bias_right(&multibuffer_snapshot);
 5320        if position.diff_base_anchor.is_some() {
 5321            return;
 5322        }
 5323        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5324        let Some(buffer) = buffer_position
 5325            .buffer_id
 5326            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5327        else {
 5328            return;
 5329        };
 5330        let buffer_snapshot = buffer.read(cx).snapshot();
 5331
 5332        let query: Option<Arc<String>> =
 5333            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5334                .map(|query| query.into());
 5335
 5336        drop(multibuffer_snapshot);
 5337
 5338        // Hide the current completions menu when query is empty. Without this, cached
 5339        // completions from before the trigger char may be reused (#32774).
 5340        if query.is_none() {
 5341            let menu_is_open = matches!(
 5342                self.context_menu.borrow().as_ref(),
 5343                Some(CodeContextMenu::Completions(_))
 5344            );
 5345            if menu_is_open {
 5346                self.hide_context_menu(window, cx);
 5347            }
 5348        }
 5349
 5350        let mut ignore_word_threshold = false;
 5351        let provider = match requested_source {
 5352            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5353            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5354                ignore_word_threshold = ignore_threshold;
 5355                None
 5356            }
 5357            Some(CompletionsMenuSource::SnippetChoices) => {
 5358                log::error!("bug: SnippetChoices requested_source is not handled");
 5359                None
 5360            }
 5361        };
 5362
 5363        let sort_completions = provider
 5364            .as_ref()
 5365            .is_some_and(|provider| provider.sort_completions());
 5366
 5367        let filter_completions = provider
 5368            .as_ref()
 5369            .is_none_or(|provider| provider.filter_completions());
 5370
 5371        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5372            if filter_completions {
 5373                menu.filter(query.clone(), provider.clone(), window, cx);
 5374            }
 5375            // When `is_incomplete` is false, no need to re-query completions when the current query
 5376            // is a suffix of the initial query.
 5377            if !menu.is_incomplete {
 5378                // If the new query is a suffix of the old query (typing more characters) and
 5379                // the previous result was complete, the existing completions can be filtered.
 5380                //
 5381                // Note that this is always true for snippet completions.
 5382                let query_matches = match (&menu.initial_query, &query) {
 5383                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5384                    (None, _) => true,
 5385                    _ => false,
 5386                };
 5387                if query_matches {
 5388                    let position_matches = if menu.initial_position == position {
 5389                        true
 5390                    } else {
 5391                        let snapshot = self.buffer.read(cx).read(cx);
 5392                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5393                    };
 5394                    if position_matches {
 5395                        return;
 5396                    }
 5397                }
 5398            }
 5399        };
 5400
 5401        let trigger_kind = match trigger {
 5402            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5403                CompletionTriggerKind::TRIGGER_CHARACTER
 5404            }
 5405            _ => CompletionTriggerKind::INVOKED,
 5406        };
 5407        let completion_context = CompletionContext {
 5408            trigger_character: trigger.and_then(|trigger| {
 5409                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5410                    Some(String::from(trigger))
 5411                } else {
 5412                    None
 5413                }
 5414            }),
 5415            trigger_kind,
 5416        };
 5417
 5418        let Anchor {
 5419            excerpt_id: buffer_excerpt_id,
 5420            text_anchor: buffer_position,
 5421            ..
 5422        } = buffer_position;
 5423
 5424        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5425            buffer_snapshot.surrounding_word(buffer_position, None)
 5426        {
 5427            let word_to_exclude = buffer_snapshot
 5428                .text_for_range(word_range.clone())
 5429                .collect::<String>();
 5430            (
 5431                buffer_snapshot.anchor_before(word_range.start)
 5432                    ..buffer_snapshot.anchor_after(buffer_position),
 5433                Some(word_to_exclude),
 5434            )
 5435        } else {
 5436            (buffer_position..buffer_position, None)
 5437        };
 5438
 5439        let language = buffer_snapshot
 5440            .language_at(buffer_position)
 5441            .map(|language| language.name());
 5442
 5443        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5444            .completions
 5445            .clone();
 5446
 5447        let show_completion_documentation = buffer_snapshot
 5448            .settings_at(buffer_position, cx)
 5449            .show_completion_documentation;
 5450
 5451        // The document can be large, so stay in reasonable bounds when searching for words,
 5452        // otherwise completion pop-up might be slow to appear.
 5453        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5454        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5455        let min_word_search = buffer_snapshot.clip_point(
 5456            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5457            Bias::Left,
 5458        );
 5459        let max_word_search = buffer_snapshot.clip_point(
 5460            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5461            Bias::Right,
 5462        );
 5463        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5464            ..buffer_snapshot.point_to_offset(max_word_search);
 5465
 5466        let skip_digits = query
 5467            .as_ref()
 5468            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5469
 5470        let omit_word_completions = !self.word_completions_enabled
 5471            || (!ignore_word_threshold
 5472                && match &query {
 5473                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5474                    None => completion_settings.words_min_length != 0,
 5475                });
 5476
 5477        let (mut words, provider_responses) = match &provider {
 5478            Some(provider) => {
 5479                let provider_responses = provider.completions(
 5480                    buffer_excerpt_id,
 5481                    &buffer,
 5482                    buffer_position,
 5483                    completion_context,
 5484                    window,
 5485                    cx,
 5486                );
 5487
 5488                let words = match (omit_word_completions, completion_settings.words) {
 5489                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5490                        Task::ready(BTreeMap::default())
 5491                    }
 5492                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5493                        .background_spawn(async move {
 5494                            buffer_snapshot.words_in_range(WordsQuery {
 5495                                fuzzy_contents: None,
 5496                                range: word_search_range,
 5497                                skip_digits,
 5498                            })
 5499                        }),
 5500                };
 5501
 5502                (words, provider_responses)
 5503            }
 5504            None => {
 5505                let words = if omit_word_completions {
 5506                    Task::ready(BTreeMap::default())
 5507                } else {
 5508                    cx.background_spawn(async move {
 5509                        buffer_snapshot.words_in_range(WordsQuery {
 5510                            fuzzy_contents: None,
 5511                            range: word_search_range,
 5512                            skip_digits,
 5513                        })
 5514                    })
 5515                };
 5516                (words, Task::ready(Ok(Vec::new())))
 5517            }
 5518        };
 5519
 5520        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5521
 5522        let id = post_inc(&mut self.next_completion_id);
 5523        let task = cx.spawn_in(window, async move |editor, cx| {
 5524            let Ok(()) = editor.update(cx, |this, _| {
 5525                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5526            }) else {
 5527                return;
 5528            };
 5529
 5530            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5531            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5532            let mut completions = Vec::new();
 5533            let mut is_incomplete = false;
 5534            let mut display_options: Option<CompletionDisplayOptions> = None;
 5535            if let Some(provider_responses) = provider_responses.await.log_err()
 5536                && !provider_responses.is_empty()
 5537            {
 5538                for response in provider_responses {
 5539                    completions.extend(response.completions);
 5540                    is_incomplete = is_incomplete || response.is_incomplete;
 5541                    match display_options.as_mut() {
 5542                        None => {
 5543                            display_options = Some(response.display_options);
 5544                        }
 5545                        Some(options) => options.merge(&response.display_options),
 5546                    }
 5547                }
 5548                if completion_settings.words == WordsCompletionMode::Fallback {
 5549                    words = Task::ready(BTreeMap::default());
 5550                }
 5551            }
 5552            let display_options = display_options.unwrap_or_default();
 5553
 5554            let mut words = words.await;
 5555            if let Some(word_to_exclude) = &word_to_exclude {
 5556                words.remove(word_to_exclude);
 5557            }
 5558            for lsp_completion in &completions {
 5559                words.remove(&lsp_completion.new_text);
 5560            }
 5561            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5562                replace_range: word_replace_range.clone(),
 5563                new_text: word.clone(),
 5564                label: CodeLabel::plain(word, None),
 5565                icon_path: None,
 5566                documentation: None,
 5567                source: CompletionSource::BufferWord {
 5568                    word_range,
 5569                    resolved: false,
 5570                },
 5571                insert_text_mode: Some(InsertTextMode::AS_IS),
 5572                confirm: None,
 5573            }));
 5574
 5575            let menu = if completions.is_empty() {
 5576                None
 5577            } else {
 5578                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5579                    let languages = editor
 5580                        .workspace
 5581                        .as_ref()
 5582                        .and_then(|(workspace, _)| workspace.upgrade())
 5583                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5584                    let menu = CompletionsMenu::new(
 5585                        id,
 5586                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5587                        sort_completions,
 5588                        show_completion_documentation,
 5589                        position,
 5590                        query.clone(),
 5591                        is_incomplete,
 5592                        buffer.clone(),
 5593                        completions.into(),
 5594                        display_options,
 5595                        snippet_sort_order,
 5596                        languages,
 5597                        language,
 5598                        cx,
 5599                    );
 5600
 5601                    let query = if filter_completions { query } else { None };
 5602                    let matches_task = if let Some(query) = query {
 5603                        menu.do_async_filtering(query, cx)
 5604                    } else {
 5605                        Task::ready(menu.unfiltered_matches())
 5606                    };
 5607                    (menu, matches_task)
 5608                }) else {
 5609                    return;
 5610                };
 5611
 5612                let matches = matches_task.await;
 5613
 5614                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5615                    // Newer menu already set, so exit.
 5616                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5617                        editor.context_menu.borrow().as_ref()
 5618                        && prev_menu.id > id
 5619                    {
 5620                        return;
 5621                    };
 5622
 5623                    // Only valid to take prev_menu because it the new menu is immediately set
 5624                    // below, or the menu is hidden.
 5625                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5626                        editor.context_menu.borrow_mut().take()
 5627                    {
 5628                        let position_matches =
 5629                            if prev_menu.initial_position == menu.initial_position {
 5630                                true
 5631                            } else {
 5632                                let snapshot = editor.buffer.read(cx).read(cx);
 5633                                prev_menu.initial_position.to_offset(&snapshot)
 5634                                    == menu.initial_position.to_offset(&snapshot)
 5635                            };
 5636                        if position_matches {
 5637                            // Preserve markdown cache before `set_filter_results` because it will
 5638                            // try to populate the documentation cache.
 5639                            menu.preserve_markdown_cache(prev_menu);
 5640                        }
 5641                    };
 5642
 5643                    menu.set_filter_results(matches, provider, window, cx);
 5644                }) else {
 5645                    return;
 5646                };
 5647
 5648                menu.visible().then_some(menu)
 5649            };
 5650
 5651            editor
 5652                .update_in(cx, |editor, window, cx| {
 5653                    if editor.focus_handle.is_focused(window)
 5654                        && let Some(menu) = menu
 5655                    {
 5656                        *editor.context_menu.borrow_mut() =
 5657                            Some(CodeContextMenu::Completions(menu));
 5658
 5659                        crate::hover_popover::hide_hover(editor, cx);
 5660                        if editor.show_edit_predictions_in_menu() {
 5661                            editor.update_visible_edit_prediction(window, cx);
 5662                        } else {
 5663                            editor.discard_edit_prediction(false, cx);
 5664                        }
 5665
 5666                        cx.notify();
 5667                        return;
 5668                    }
 5669
 5670                    if editor.completion_tasks.len() <= 1 {
 5671                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5672                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5673                        // If it was already hidden and we don't show edit predictions in the menu,
 5674                        // we should also show the edit prediction when available.
 5675                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5676                            editor.update_visible_edit_prediction(window, cx);
 5677                        }
 5678                    }
 5679                })
 5680                .ok();
 5681        });
 5682
 5683        self.completion_tasks.push((id, task));
 5684    }
 5685
 5686    #[cfg(feature = "test-support")]
 5687    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5688        let menu = self.context_menu.borrow();
 5689        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5690            let completions = menu.completions.borrow();
 5691            Some(completions.to_vec())
 5692        } else {
 5693            None
 5694        }
 5695    }
 5696
 5697    pub fn with_completions_menu_matching_id<R>(
 5698        &self,
 5699        id: CompletionId,
 5700        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5701    ) -> R {
 5702        let mut context_menu = self.context_menu.borrow_mut();
 5703        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5704            return f(None);
 5705        };
 5706        if completions_menu.id != id {
 5707            return f(None);
 5708        }
 5709        f(Some(completions_menu))
 5710    }
 5711
 5712    pub fn confirm_completion(
 5713        &mut self,
 5714        action: &ConfirmCompletion,
 5715        window: &mut Window,
 5716        cx: &mut Context<Self>,
 5717    ) -> Option<Task<Result<()>>> {
 5718        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5719        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5720    }
 5721
 5722    pub fn confirm_completion_insert(
 5723        &mut self,
 5724        _: &ConfirmCompletionInsert,
 5725        window: &mut Window,
 5726        cx: &mut Context<Self>,
 5727    ) -> Option<Task<Result<()>>> {
 5728        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5729        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5730    }
 5731
 5732    pub fn confirm_completion_replace(
 5733        &mut self,
 5734        _: &ConfirmCompletionReplace,
 5735        window: &mut Window,
 5736        cx: &mut Context<Self>,
 5737    ) -> Option<Task<Result<()>>> {
 5738        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5739        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5740    }
 5741
 5742    pub fn compose_completion(
 5743        &mut self,
 5744        action: &ComposeCompletion,
 5745        window: &mut Window,
 5746        cx: &mut Context<Self>,
 5747    ) -> Option<Task<Result<()>>> {
 5748        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5749        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5750    }
 5751
 5752    fn do_completion(
 5753        &mut self,
 5754        item_ix: Option<usize>,
 5755        intent: CompletionIntent,
 5756        window: &mut Window,
 5757        cx: &mut Context<Editor>,
 5758    ) -> Option<Task<Result<()>>> {
 5759        use language::ToOffset as _;
 5760
 5761        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5762        else {
 5763            return None;
 5764        };
 5765
 5766        let candidate_id = {
 5767            let entries = completions_menu.entries.borrow();
 5768            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5769            if self.show_edit_predictions_in_menu() {
 5770                self.discard_edit_prediction(true, cx);
 5771            }
 5772            mat.candidate_id
 5773        };
 5774
 5775        let completion = completions_menu
 5776            .completions
 5777            .borrow()
 5778            .get(candidate_id)?
 5779            .clone();
 5780        cx.stop_propagation();
 5781
 5782        let buffer_handle = completions_menu.buffer.clone();
 5783
 5784        let CompletionEdit {
 5785            new_text,
 5786            snippet,
 5787            replace_range,
 5788        } = process_completion_for_edit(
 5789            &completion,
 5790            intent,
 5791            &buffer_handle,
 5792            &completions_menu.initial_position.text_anchor,
 5793            cx,
 5794        );
 5795
 5796        let buffer = buffer_handle.read(cx);
 5797        let snapshot = self.buffer.read(cx).snapshot(cx);
 5798        let newest_anchor = self.selections.newest_anchor();
 5799        let replace_range_multibuffer = {
 5800            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5801            excerpt.map_range_from_buffer(replace_range.clone())
 5802        };
 5803        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5804            return None;
 5805        }
 5806
 5807        let old_text = buffer
 5808            .text_for_range(replace_range.clone())
 5809            .collect::<String>();
 5810        let lookbehind = newest_anchor
 5811            .start
 5812            .text_anchor
 5813            .to_offset(buffer)
 5814            .saturating_sub(replace_range.start);
 5815        let lookahead = replace_range
 5816            .end
 5817            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5818        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5819        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5820
 5821        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5822        let mut ranges = Vec::new();
 5823        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5824
 5825        for selection in &selections {
 5826            let range = if selection.id == newest_anchor.id {
 5827                replace_range_multibuffer.clone()
 5828            } else {
 5829                let mut range = selection.range();
 5830
 5831                // if prefix is present, don't duplicate it
 5832                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5833                    range.start = range.start.saturating_sub(lookbehind);
 5834
 5835                    // if suffix is also present, mimic the newest cursor and replace it
 5836                    if selection.id != newest_anchor.id
 5837                        && snapshot.contains_str_at(range.end, suffix)
 5838                    {
 5839                        range.end += lookahead;
 5840                    }
 5841                }
 5842                range
 5843            };
 5844
 5845            ranges.push(range.clone());
 5846
 5847            if !self.linked_edit_ranges.is_empty() {
 5848                let start_anchor = snapshot.anchor_before(range.start);
 5849                let end_anchor = snapshot.anchor_after(range.end);
 5850                if let Some(ranges) = self
 5851                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5852                {
 5853                    for (buffer, edits) in ranges {
 5854                        linked_edits
 5855                            .entry(buffer.clone())
 5856                            .or_default()
 5857                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5858                    }
 5859                }
 5860            }
 5861        }
 5862
 5863        let common_prefix_len = old_text
 5864            .chars()
 5865            .zip(new_text.chars())
 5866            .take_while(|(a, b)| a == b)
 5867            .map(|(a, _)| a.len_utf8())
 5868            .sum::<usize>();
 5869
 5870        cx.emit(EditorEvent::InputHandled {
 5871            utf16_range_to_replace: None,
 5872            text: new_text[common_prefix_len..].into(),
 5873        });
 5874
 5875        self.transact(window, cx, |editor, window, cx| {
 5876            if let Some(mut snippet) = snippet {
 5877                snippet.text = new_text.to_string();
 5878                editor
 5879                    .insert_snippet(&ranges, snippet, window, cx)
 5880                    .log_err();
 5881            } else {
 5882                editor.buffer.update(cx, |multi_buffer, cx| {
 5883                    let auto_indent = match completion.insert_text_mode {
 5884                        Some(InsertTextMode::AS_IS) => None,
 5885                        _ => editor.autoindent_mode.clone(),
 5886                    };
 5887                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5888                    multi_buffer.edit(edits, auto_indent, cx);
 5889                });
 5890            }
 5891            for (buffer, edits) in linked_edits {
 5892                buffer.update(cx, |buffer, cx| {
 5893                    let snapshot = buffer.snapshot();
 5894                    let edits = edits
 5895                        .into_iter()
 5896                        .map(|(range, text)| {
 5897                            use text::ToPoint as TP;
 5898                            let end_point = TP::to_point(&range.end, &snapshot);
 5899                            let start_point = TP::to_point(&range.start, &snapshot);
 5900                            (start_point..end_point, text)
 5901                        })
 5902                        .sorted_by_key(|(range, _)| range.start);
 5903                    buffer.edit(edits, None, cx);
 5904                })
 5905            }
 5906
 5907            editor.refresh_edit_prediction(true, false, window, cx);
 5908        });
 5909        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 5910
 5911        let show_new_completions_on_confirm = completion
 5912            .confirm
 5913            .as_ref()
 5914            .is_some_and(|confirm| confirm(intent, window, cx));
 5915        if show_new_completions_on_confirm {
 5916            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5917        }
 5918
 5919        let provider = self.completion_provider.as_ref()?;
 5920        drop(completion);
 5921        let apply_edits = provider.apply_additional_edits_for_completion(
 5922            buffer_handle,
 5923            completions_menu.completions.clone(),
 5924            candidate_id,
 5925            true,
 5926            cx,
 5927        );
 5928
 5929        let editor_settings = EditorSettings::get_global(cx);
 5930        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5931            // After the code completion is finished, users often want to know what signatures are needed.
 5932            // so we should automatically call signature_help
 5933            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5934        }
 5935
 5936        Some(cx.foreground_executor().spawn(async move {
 5937            apply_edits.await?;
 5938            Ok(())
 5939        }))
 5940    }
 5941
 5942    pub fn toggle_code_actions(
 5943        &mut self,
 5944        action: &ToggleCodeActions,
 5945        window: &mut Window,
 5946        cx: &mut Context<Self>,
 5947    ) {
 5948        let quick_launch = action.quick_launch;
 5949        let mut context_menu = self.context_menu.borrow_mut();
 5950        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5951            if code_actions.deployed_from == action.deployed_from {
 5952                // Toggle if we're selecting the same one
 5953                *context_menu = None;
 5954                cx.notify();
 5955                return;
 5956            } else {
 5957                // Otherwise, clear it and start a new one
 5958                *context_menu = None;
 5959                cx.notify();
 5960            }
 5961        }
 5962        drop(context_menu);
 5963        let snapshot = self.snapshot(window, cx);
 5964        let deployed_from = action.deployed_from.clone();
 5965        let action = action.clone();
 5966        self.completion_tasks.clear();
 5967        self.discard_edit_prediction(false, cx);
 5968
 5969        let multibuffer_point = match &action.deployed_from {
 5970            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5971                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5972            }
 5973            _ => self
 5974                .selections
 5975                .newest::<Point>(&snapshot.display_snapshot)
 5976                .head(),
 5977        };
 5978        let Some((buffer, buffer_row)) = snapshot
 5979            .buffer_snapshot()
 5980            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5981            .and_then(|(buffer_snapshot, range)| {
 5982                self.buffer()
 5983                    .read(cx)
 5984                    .buffer(buffer_snapshot.remote_id())
 5985                    .map(|buffer| (buffer, range.start.row))
 5986            })
 5987        else {
 5988            return;
 5989        };
 5990        let buffer_id = buffer.read(cx).remote_id();
 5991        let tasks = self
 5992            .tasks
 5993            .get(&(buffer_id, buffer_row))
 5994            .map(|t| Arc::new(t.to_owned()));
 5995
 5996        if !self.focus_handle.is_focused(window) {
 5997            return;
 5998        }
 5999        let project = self.project.clone();
 6000
 6001        let code_actions_task = match deployed_from {
 6002            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6003            _ => self.code_actions(buffer_row, window, cx),
 6004        };
 6005
 6006        let runnable_task = match deployed_from {
 6007            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6008            _ => {
 6009                let mut task_context_task = Task::ready(None);
 6010                if let Some(tasks) = &tasks
 6011                    && let Some(project) = project
 6012                {
 6013                    task_context_task =
 6014                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6015                }
 6016
 6017                cx.spawn_in(window, {
 6018                    let buffer = buffer.clone();
 6019                    async move |editor, cx| {
 6020                        let task_context = task_context_task.await;
 6021
 6022                        let resolved_tasks =
 6023                            tasks
 6024                                .zip(task_context.clone())
 6025                                .map(|(tasks, task_context)| ResolvedTasks {
 6026                                    templates: tasks.resolve(&task_context).collect(),
 6027                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6028                                        multibuffer_point.row,
 6029                                        tasks.column,
 6030                                    )),
 6031                                });
 6032                        let debug_scenarios = editor
 6033                            .update(cx, |editor, cx| {
 6034                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6035                            })?
 6036                            .await;
 6037                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6038                    }
 6039                })
 6040            }
 6041        };
 6042
 6043        cx.spawn_in(window, async move |editor, cx| {
 6044            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6045            let code_actions = code_actions_task.await;
 6046            let spawn_straight_away = quick_launch
 6047                && resolved_tasks
 6048                    .as_ref()
 6049                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6050                && code_actions
 6051                    .as_ref()
 6052                    .is_none_or(|actions| actions.is_empty())
 6053                && debug_scenarios.is_empty();
 6054
 6055            editor.update_in(cx, |editor, window, cx| {
 6056                crate::hover_popover::hide_hover(editor, cx);
 6057                let actions = CodeActionContents::new(
 6058                    resolved_tasks,
 6059                    code_actions,
 6060                    debug_scenarios,
 6061                    task_context.unwrap_or_default(),
 6062                );
 6063
 6064                // Don't show the menu if there are no actions available
 6065                if actions.is_empty() {
 6066                    cx.notify();
 6067                    return Task::ready(Ok(()));
 6068                }
 6069
 6070                *editor.context_menu.borrow_mut() =
 6071                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6072                        buffer,
 6073                        actions,
 6074                        selected_item: Default::default(),
 6075                        scroll_handle: UniformListScrollHandle::default(),
 6076                        deployed_from,
 6077                    }));
 6078                cx.notify();
 6079                if spawn_straight_away
 6080                    && let Some(task) = editor.confirm_code_action(
 6081                        &ConfirmCodeAction { item_ix: Some(0) },
 6082                        window,
 6083                        cx,
 6084                    )
 6085                {
 6086                    return task;
 6087                }
 6088
 6089                Task::ready(Ok(()))
 6090            })
 6091        })
 6092        .detach_and_log_err(cx);
 6093    }
 6094
 6095    fn debug_scenarios(
 6096        &mut self,
 6097        resolved_tasks: &Option<ResolvedTasks>,
 6098        buffer: &Entity<Buffer>,
 6099        cx: &mut App,
 6100    ) -> Task<Vec<task::DebugScenario>> {
 6101        maybe!({
 6102            let project = self.project()?;
 6103            let dap_store = project.read(cx).dap_store();
 6104            let mut scenarios = vec![];
 6105            let resolved_tasks = resolved_tasks.as_ref()?;
 6106            let buffer = buffer.read(cx);
 6107            let language = buffer.language()?;
 6108            let file = buffer.file();
 6109            let debug_adapter = language_settings(language.name().into(), file, cx)
 6110                .debuggers
 6111                .first()
 6112                .map(SharedString::from)
 6113                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6114
 6115            dap_store.update(cx, |dap_store, cx| {
 6116                for (_, task) in &resolved_tasks.templates {
 6117                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6118                        task.original_task().clone(),
 6119                        debug_adapter.clone().into(),
 6120                        task.display_label().to_owned().into(),
 6121                        cx,
 6122                    );
 6123                    scenarios.push(maybe_scenario);
 6124                }
 6125            });
 6126            Some(cx.background_spawn(async move {
 6127                futures::future::join_all(scenarios)
 6128                    .await
 6129                    .into_iter()
 6130                    .flatten()
 6131                    .collect::<Vec<_>>()
 6132            }))
 6133        })
 6134        .unwrap_or_else(|| Task::ready(vec![]))
 6135    }
 6136
 6137    fn code_actions(
 6138        &mut self,
 6139        buffer_row: u32,
 6140        window: &mut Window,
 6141        cx: &mut Context<Self>,
 6142    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6143        let mut task = self.code_actions_task.take();
 6144        cx.spawn_in(window, async move |editor, cx| {
 6145            while let Some(prev_task) = task {
 6146                prev_task.await.log_err();
 6147                task = editor
 6148                    .update(cx, |this, _| this.code_actions_task.take())
 6149                    .ok()?;
 6150            }
 6151
 6152            editor
 6153                .update(cx, |editor, cx| {
 6154                    editor
 6155                        .available_code_actions
 6156                        .clone()
 6157                        .and_then(|(location, code_actions)| {
 6158                            let snapshot = location.buffer.read(cx).snapshot();
 6159                            let point_range = location.range.to_point(&snapshot);
 6160                            let point_range = point_range.start.row..=point_range.end.row;
 6161                            if point_range.contains(&buffer_row) {
 6162                                Some(code_actions)
 6163                            } else {
 6164                                None
 6165                            }
 6166                        })
 6167                })
 6168                .ok()
 6169                .flatten()
 6170        })
 6171    }
 6172
 6173    pub fn confirm_code_action(
 6174        &mut self,
 6175        action: &ConfirmCodeAction,
 6176        window: &mut Window,
 6177        cx: &mut Context<Self>,
 6178    ) -> Option<Task<Result<()>>> {
 6179        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6180
 6181        let actions_menu =
 6182            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6183                menu
 6184            } else {
 6185                return None;
 6186            };
 6187
 6188        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6189        let action = actions_menu.actions.get(action_ix)?;
 6190        let title = action.label();
 6191        let buffer = actions_menu.buffer;
 6192        let workspace = self.workspace()?;
 6193
 6194        match action {
 6195            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6196                workspace.update(cx, |workspace, cx| {
 6197                    workspace.schedule_resolved_task(
 6198                        task_source_kind,
 6199                        resolved_task,
 6200                        false,
 6201                        window,
 6202                        cx,
 6203                    );
 6204
 6205                    Some(Task::ready(Ok(())))
 6206                })
 6207            }
 6208            CodeActionsItem::CodeAction {
 6209                excerpt_id,
 6210                action,
 6211                provider,
 6212            } => {
 6213                let apply_code_action =
 6214                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6215                let workspace = workspace.downgrade();
 6216                Some(cx.spawn_in(window, async move |editor, cx| {
 6217                    let project_transaction = apply_code_action.await?;
 6218                    Self::open_project_transaction(
 6219                        &editor,
 6220                        workspace,
 6221                        project_transaction,
 6222                        title,
 6223                        cx,
 6224                    )
 6225                    .await
 6226                }))
 6227            }
 6228            CodeActionsItem::DebugScenario(scenario) => {
 6229                let context = actions_menu.actions.context;
 6230
 6231                workspace.update(cx, |workspace, cx| {
 6232                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6233                    workspace.start_debug_session(
 6234                        scenario,
 6235                        context,
 6236                        Some(buffer),
 6237                        None,
 6238                        window,
 6239                        cx,
 6240                    );
 6241                });
 6242                Some(Task::ready(Ok(())))
 6243            }
 6244        }
 6245    }
 6246
 6247    pub async fn open_project_transaction(
 6248        editor: &WeakEntity<Editor>,
 6249        workspace: WeakEntity<Workspace>,
 6250        transaction: ProjectTransaction,
 6251        title: String,
 6252        cx: &mut AsyncWindowContext,
 6253    ) -> Result<()> {
 6254        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6255        cx.update(|_, cx| {
 6256            entries.sort_unstable_by_key(|(buffer, _)| {
 6257                buffer.read(cx).file().map(|f| f.path().clone())
 6258            });
 6259        })?;
 6260        if entries.is_empty() {
 6261            return Ok(());
 6262        }
 6263
 6264        // If the project transaction's edits are all contained within this editor, then
 6265        // avoid opening a new editor to display them.
 6266
 6267        if let [(buffer, transaction)] = &*entries {
 6268            let excerpt = editor.update(cx, |editor, cx| {
 6269                editor
 6270                    .buffer()
 6271                    .read(cx)
 6272                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6273            })?;
 6274            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6275                && excerpted_buffer == *buffer
 6276            {
 6277                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6278                    let excerpt_range = excerpt_range.to_offset(buffer);
 6279                    buffer
 6280                        .edited_ranges_for_transaction::<usize>(transaction)
 6281                        .all(|range| {
 6282                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6283                        })
 6284                })?;
 6285
 6286                if all_edits_within_excerpt {
 6287                    return Ok(());
 6288                }
 6289            }
 6290        }
 6291
 6292        let mut ranges_to_highlight = Vec::new();
 6293        let excerpt_buffer = cx.new(|cx| {
 6294            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6295            for (buffer_handle, transaction) in &entries {
 6296                let edited_ranges = buffer_handle
 6297                    .read(cx)
 6298                    .edited_ranges_for_transaction::<Point>(transaction)
 6299                    .collect::<Vec<_>>();
 6300                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6301                    PathKey::for_buffer(buffer_handle, cx),
 6302                    buffer_handle.clone(),
 6303                    edited_ranges,
 6304                    multibuffer_context_lines(cx),
 6305                    cx,
 6306                );
 6307
 6308                ranges_to_highlight.extend(ranges);
 6309            }
 6310            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6311            multibuffer
 6312        })?;
 6313
 6314        workspace.update_in(cx, |workspace, window, cx| {
 6315            let project = workspace.project().clone();
 6316            let editor =
 6317                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6318            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6319            editor.update(cx, |editor, cx| {
 6320                editor.highlight_background::<Self>(
 6321                    &ranges_to_highlight,
 6322                    |theme| theme.colors().editor_highlighted_line_background,
 6323                    cx,
 6324                );
 6325            });
 6326        })?;
 6327
 6328        Ok(())
 6329    }
 6330
 6331    pub fn clear_code_action_providers(&mut self) {
 6332        self.code_action_providers.clear();
 6333        self.available_code_actions.take();
 6334    }
 6335
 6336    pub fn add_code_action_provider(
 6337        &mut self,
 6338        provider: Rc<dyn CodeActionProvider>,
 6339        window: &mut Window,
 6340        cx: &mut Context<Self>,
 6341    ) {
 6342        if self
 6343            .code_action_providers
 6344            .iter()
 6345            .any(|existing_provider| existing_provider.id() == provider.id())
 6346        {
 6347            return;
 6348        }
 6349
 6350        self.code_action_providers.push(provider);
 6351        self.refresh_code_actions(window, cx);
 6352    }
 6353
 6354    pub fn remove_code_action_provider(
 6355        &mut self,
 6356        id: Arc<str>,
 6357        window: &mut Window,
 6358        cx: &mut Context<Self>,
 6359    ) {
 6360        self.code_action_providers
 6361            .retain(|provider| provider.id() != id);
 6362        self.refresh_code_actions(window, cx);
 6363    }
 6364
 6365    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6366        !self.code_action_providers.is_empty()
 6367            && EditorSettings::get_global(cx).toolbar.code_actions
 6368    }
 6369
 6370    pub fn has_available_code_actions(&self) -> bool {
 6371        self.available_code_actions
 6372            .as_ref()
 6373            .is_some_and(|(_, actions)| !actions.is_empty())
 6374    }
 6375
 6376    fn render_inline_code_actions(
 6377        &self,
 6378        icon_size: ui::IconSize,
 6379        display_row: DisplayRow,
 6380        is_active: bool,
 6381        cx: &mut Context<Self>,
 6382    ) -> AnyElement {
 6383        let show_tooltip = !self.context_menu_visible();
 6384        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6385            .icon_size(icon_size)
 6386            .shape(ui::IconButtonShape::Square)
 6387            .icon_color(ui::Color::Hidden)
 6388            .toggle_state(is_active)
 6389            .when(show_tooltip, |this| {
 6390                this.tooltip({
 6391                    let focus_handle = self.focus_handle.clone();
 6392                    move |_window, cx| {
 6393                        Tooltip::for_action_in(
 6394                            "Toggle Code Actions",
 6395                            &ToggleCodeActions {
 6396                                deployed_from: None,
 6397                                quick_launch: false,
 6398                            },
 6399                            &focus_handle,
 6400                            cx,
 6401                        )
 6402                    }
 6403                })
 6404            })
 6405            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6406                window.focus(&editor.focus_handle(cx));
 6407                editor.toggle_code_actions(
 6408                    &crate::actions::ToggleCodeActions {
 6409                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6410                            display_row,
 6411                        )),
 6412                        quick_launch: false,
 6413                    },
 6414                    window,
 6415                    cx,
 6416                );
 6417            }))
 6418            .into_any_element()
 6419    }
 6420
 6421    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6422        &self.context_menu
 6423    }
 6424
 6425    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6426        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6427            cx.background_executor()
 6428                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6429                .await;
 6430
 6431            let (start_buffer, start, _, end, newest_selection) = this
 6432                .update(cx, |this, cx| {
 6433                    let newest_selection = this.selections.newest_anchor().clone();
 6434                    if newest_selection.head().diff_base_anchor.is_some() {
 6435                        return None;
 6436                    }
 6437                    let display_snapshot = this.display_snapshot(cx);
 6438                    let newest_selection_adjusted =
 6439                        this.selections.newest_adjusted(&display_snapshot);
 6440                    let buffer = this.buffer.read(cx);
 6441
 6442                    let (start_buffer, start) =
 6443                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6444                    let (end_buffer, end) =
 6445                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6446
 6447                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6448                })?
 6449                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6450                .context(
 6451                    "Expected selection to lie in a single buffer when refreshing code actions",
 6452                )?;
 6453            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6454                let providers = this.code_action_providers.clone();
 6455                let tasks = this
 6456                    .code_action_providers
 6457                    .iter()
 6458                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6459                    .collect::<Vec<_>>();
 6460                (providers, tasks)
 6461            })?;
 6462
 6463            let mut actions = Vec::new();
 6464            for (provider, provider_actions) in
 6465                providers.into_iter().zip(future::join_all(tasks).await)
 6466            {
 6467                if let Some(provider_actions) = provider_actions.log_err() {
 6468                    actions.extend(provider_actions.into_iter().map(|action| {
 6469                        AvailableCodeAction {
 6470                            excerpt_id: newest_selection.start.excerpt_id,
 6471                            action,
 6472                            provider: provider.clone(),
 6473                        }
 6474                    }));
 6475                }
 6476            }
 6477
 6478            this.update(cx, |this, cx| {
 6479                this.available_code_actions = if actions.is_empty() {
 6480                    None
 6481                } else {
 6482                    Some((
 6483                        Location {
 6484                            buffer: start_buffer,
 6485                            range: start..end,
 6486                        },
 6487                        actions.into(),
 6488                    ))
 6489                };
 6490                cx.notify();
 6491            })
 6492        }));
 6493    }
 6494
 6495    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6496        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6497            self.show_git_blame_inline = false;
 6498
 6499            self.show_git_blame_inline_delay_task =
 6500                Some(cx.spawn_in(window, async move |this, cx| {
 6501                    cx.background_executor().timer(delay).await;
 6502
 6503                    this.update(cx, |this, cx| {
 6504                        this.show_git_blame_inline = true;
 6505                        cx.notify();
 6506                    })
 6507                    .log_err();
 6508                }));
 6509        }
 6510    }
 6511
 6512    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6513        let snapshot = self.snapshot(window, cx);
 6514        let cursor = self
 6515            .selections
 6516            .newest::<Point>(&snapshot.display_snapshot)
 6517            .head();
 6518        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6519        else {
 6520            return;
 6521        };
 6522
 6523        let Some(blame) = self.blame.as_ref() else {
 6524            return;
 6525        };
 6526
 6527        let row_info = RowInfo {
 6528            buffer_id: Some(buffer.remote_id()),
 6529            buffer_row: Some(point.row),
 6530            ..Default::default()
 6531        };
 6532        let Some((buffer, blame_entry)) = blame
 6533            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6534            .flatten()
 6535        else {
 6536            return;
 6537        };
 6538
 6539        let anchor = self.selections.newest_anchor().head();
 6540        let position = self.to_pixel_point(anchor, &snapshot, window);
 6541        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6542            self.show_blame_popover(
 6543                buffer,
 6544                &blame_entry,
 6545                position + last_bounds.origin,
 6546                true,
 6547                cx,
 6548            );
 6549        };
 6550    }
 6551
 6552    fn show_blame_popover(
 6553        &mut self,
 6554        buffer: BufferId,
 6555        blame_entry: &BlameEntry,
 6556        position: gpui::Point<Pixels>,
 6557        ignore_timeout: bool,
 6558        cx: &mut Context<Self>,
 6559    ) {
 6560        if let Some(state) = &mut self.inline_blame_popover {
 6561            state.hide_task.take();
 6562        } else {
 6563            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6564            let blame_entry = blame_entry.clone();
 6565            let show_task = cx.spawn(async move |editor, cx| {
 6566                if !ignore_timeout {
 6567                    cx.background_executor()
 6568                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6569                        .await;
 6570                }
 6571                editor
 6572                    .update(cx, |editor, cx| {
 6573                        editor.inline_blame_popover_show_task.take();
 6574                        let Some(blame) = editor.blame.as_ref() else {
 6575                            return;
 6576                        };
 6577                        let blame = blame.read(cx);
 6578                        let details = blame.details_for_entry(buffer, &blame_entry);
 6579                        let markdown = cx.new(|cx| {
 6580                            Markdown::new(
 6581                                details
 6582                                    .as_ref()
 6583                                    .map(|message| message.message.clone())
 6584                                    .unwrap_or_default(),
 6585                                None,
 6586                                None,
 6587                                cx,
 6588                            )
 6589                        });
 6590                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6591                            position,
 6592                            hide_task: None,
 6593                            popover_bounds: None,
 6594                            popover_state: InlineBlamePopoverState {
 6595                                scroll_handle: ScrollHandle::new(),
 6596                                commit_message: details,
 6597                                markdown,
 6598                            },
 6599                            keyboard_grace: ignore_timeout,
 6600                        });
 6601                        cx.notify();
 6602                    })
 6603                    .ok();
 6604            });
 6605            self.inline_blame_popover_show_task = Some(show_task);
 6606        }
 6607    }
 6608
 6609    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6610        self.inline_blame_popover_show_task.take();
 6611        if let Some(state) = &mut self.inline_blame_popover {
 6612            let hide_task = cx.spawn(async move |editor, cx| {
 6613                if !ignore_timeout {
 6614                    cx.background_executor()
 6615                        .timer(std::time::Duration::from_millis(100))
 6616                        .await;
 6617                }
 6618                editor
 6619                    .update(cx, |editor, cx| {
 6620                        editor.inline_blame_popover.take();
 6621                        cx.notify();
 6622                    })
 6623                    .ok();
 6624            });
 6625            state.hide_task = Some(hide_task);
 6626            true
 6627        } else {
 6628            false
 6629        }
 6630    }
 6631
 6632    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6633        if self.pending_rename.is_some() {
 6634            return None;
 6635        }
 6636
 6637        let provider = self.semantics_provider.clone()?;
 6638        let buffer = self.buffer.read(cx);
 6639        let newest_selection = self.selections.newest_anchor().clone();
 6640        let cursor_position = newest_selection.head();
 6641        let (cursor_buffer, cursor_buffer_position) =
 6642            buffer.text_anchor_for_position(cursor_position, cx)?;
 6643        let (tail_buffer, tail_buffer_position) =
 6644            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6645        if cursor_buffer != tail_buffer {
 6646            return None;
 6647        }
 6648
 6649        let snapshot = cursor_buffer.read(cx).snapshot();
 6650        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6651        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6652        if start_word_range != end_word_range {
 6653            self.document_highlights_task.take();
 6654            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6655            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6656            return None;
 6657        }
 6658
 6659        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6660        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6661            cx.background_executor()
 6662                .timer(Duration::from_millis(debounce))
 6663                .await;
 6664
 6665            let highlights = if let Some(highlights) = cx
 6666                .update(|cx| {
 6667                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6668                })
 6669                .ok()
 6670                .flatten()
 6671            {
 6672                highlights.await.log_err()
 6673            } else {
 6674                None
 6675            };
 6676
 6677            if let Some(highlights) = highlights {
 6678                this.update(cx, |this, cx| {
 6679                    if this.pending_rename.is_some() {
 6680                        return;
 6681                    }
 6682
 6683                    let buffer = this.buffer.read(cx);
 6684                    if buffer
 6685                        .text_anchor_for_position(cursor_position, cx)
 6686                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6687                    {
 6688                        return;
 6689                    }
 6690
 6691                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6692                    let mut write_ranges = Vec::new();
 6693                    let mut read_ranges = Vec::new();
 6694                    for highlight in highlights {
 6695                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6696                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6697                        {
 6698                            let start = highlight
 6699                                .range
 6700                                .start
 6701                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6702                            let end = highlight
 6703                                .range
 6704                                .end
 6705                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6706                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6707                                continue;
 6708                            }
 6709
 6710                            let range =
 6711                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6712                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6713                                write_ranges.push(range);
 6714                            } else {
 6715                                read_ranges.push(range);
 6716                            }
 6717                        }
 6718                    }
 6719
 6720                    this.highlight_background::<DocumentHighlightRead>(
 6721                        &read_ranges,
 6722                        |theme| theme.colors().editor_document_highlight_read_background,
 6723                        cx,
 6724                    );
 6725                    this.highlight_background::<DocumentHighlightWrite>(
 6726                        &write_ranges,
 6727                        |theme| theme.colors().editor_document_highlight_write_background,
 6728                        cx,
 6729                    );
 6730                    cx.notify();
 6731                })
 6732                .log_err();
 6733            }
 6734        }));
 6735        None
 6736    }
 6737
 6738    fn prepare_highlight_query_from_selection(
 6739        &mut self,
 6740        cx: &mut Context<Editor>,
 6741    ) -> Option<(String, Range<Anchor>)> {
 6742        if matches!(self.mode, EditorMode::SingleLine) {
 6743            return None;
 6744        }
 6745        if !EditorSettings::get_global(cx).selection_highlight {
 6746            return None;
 6747        }
 6748        if self.selections.count() != 1 || self.selections.line_mode() {
 6749            return None;
 6750        }
 6751        let selection = self.selections.newest_anchor();
 6752        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6753        let selection_point_range = selection.start.to_point(&multi_buffer_snapshot)
 6754            ..selection.end.to_point(&multi_buffer_snapshot);
 6755        // If the selection spans multiple rows OR it is empty
 6756        if selection_point_range.start.row != selection_point_range.end.row
 6757            || selection_point_range.start.column == selection_point_range.end.column
 6758        {
 6759            return None;
 6760        }
 6761
 6762        let query = multi_buffer_snapshot
 6763            .text_for_range(selection.range())
 6764            .collect::<String>();
 6765        if query.trim().is_empty() {
 6766            return None;
 6767        }
 6768        Some((query, selection.range()))
 6769    }
 6770
 6771    fn update_selection_occurrence_highlights(
 6772        &mut self,
 6773        query_text: String,
 6774        query_range: Range<Anchor>,
 6775        multi_buffer_range_to_query: Range<Point>,
 6776        use_debounce: bool,
 6777        window: &mut Window,
 6778        cx: &mut Context<Editor>,
 6779    ) -> Task<()> {
 6780        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6781        cx.spawn_in(window, async move |editor, cx| {
 6782            if use_debounce {
 6783                cx.background_executor()
 6784                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6785                    .await;
 6786            }
 6787            let match_task = cx.background_spawn(async move {
 6788                let buffer_ranges = multi_buffer_snapshot
 6789                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6790                    .into_iter()
 6791                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6792                let mut match_ranges = Vec::new();
 6793                let Ok(regex) = project::search::SearchQuery::text(
 6794                    query_text.clone(),
 6795                    false,
 6796                    false,
 6797                    false,
 6798                    Default::default(),
 6799                    Default::default(),
 6800                    false,
 6801                    None,
 6802                ) else {
 6803                    return Vec::default();
 6804                };
 6805                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6806                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6807                    match_ranges.extend(
 6808                        regex
 6809                            .search(buffer_snapshot, Some(search_range.clone()))
 6810                            .await
 6811                            .into_iter()
 6812                            .filter_map(|match_range| {
 6813                                let match_start = buffer_snapshot
 6814                                    .anchor_after(search_range.start + match_range.start);
 6815                                let match_end = buffer_snapshot
 6816                                    .anchor_before(search_range.start + match_range.end);
 6817                                let match_anchor_range = Anchor::range_in_buffer(
 6818                                    excerpt_id,
 6819                                    buffer_snapshot.remote_id(),
 6820                                    match_start..match_end,
 6821                                );
 6822                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6823                            }),
 6824                    );
 6825                }
 6826                match_ranges
 6827            });
 6828            let match_ranges = match_task.await;
 6829            editor
 6830                .update_in(cx, |editor, _, cx| {
 6831                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6832                    if !match_ranges.is_empty() {
 6833                        editor.highlight_background::<SelectedTextHighlight>(
 6834                            &match_ranges,
 6835                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6836                            cx,
 6837                        )
 6838                    }
 6839                })
 6840                .log_err();
 6841        })
 6842    }
 6843
 6844    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6845        struct NewlineFold;
 6846        let type_id = std::any::TypeId::of::<NewlineFold>();
 6847        if !self.mode.is_single_line() {
 6848            return;
 6849        }
 6850        let snapshot = self.snapshot(window, cx);
 6851        if snapshot.buffer_snapshot().max_point().row == 0 {
 6852            return;
 6853        }
 6854        let task = cx.background_spawn(async move {
 6855            let new_newlines = snapshot
 6856                .buffer_chars_at(0)
 6857                .filter_map(|(c, i)| {
 6858                    if c == '\n' {
 6859                        Some(
 6860                            snapshot.buffer_snapshot().anchor_after(i)
 6861                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 6862                        )
 6863                    } else {
 6864                        None
 6865                    }
 6866                })
 6867                .collect::<Vec<_>>();
 6868            let existing_newlines = snapshot
 6869                .folds_in_range(0..snapshot.buffer_snapshot().len())
 6870                .filter_map(|fold| {
 6871                    if fold.placeholder.type_tag == Some(type_id) {
 6872                        Some(fold.range.start..fold.range.end)
 6873                    } else {
 6874                        None
 6875                    }
 6876                })
 6877                .collect::<Vec<_>>();
 6878
 6879            (new_newlines, existing_newlines)
 6880        });
 6881        self.folding_newlines = cx.spawn(async move |this, cx| {
 6882            let (new_newlines, existing_newlines) = task.await;
 6883            if new_newlines == existing_newlines {
 6884                return;
 6885            }
 6886            let placeholder = FoldPlaceholder {
 6887                render: Arc::new(move |_, _, cx| {
 6888                    div()
 6889                        .bg(cx.theme().status().hint_background)
 6890                        .border_b_1()
 6891                        .size_full()
 6892                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6893                        .border_color(cx.theme().status().hint)
 6894                        .child("\\n")
 6895                        .into_any()
 6896                }),
 6897                constrain_width: false,
 6898                merge_adjacent: false,
 6899                type_tag: Some(type_id),
 6900            };
 6901            let creases = new_newlines
 6902                .into_iter()
 6903                .map(|range| Crease::simple(range, placeholder.clone()))
 6904                .collect();
 6905            this.update(cx, |this, cx| {
 6906                this.display_map.update(cx, |display_map, cx| {
 6907                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6908                    display_map.fold(creases, cx);
 6909                });
 6910            })
 6911            .ok();
 6912        });
 6913    }
 6914
 6915    fn refresh_selected_text_highlights(
 6916        &mut self,
 6917        on_buffer_edit: bool,
 6918        window: &mut Window,
 6919        cx: &mut Context<Editor>,
 6920    ) {
 6921        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6922        else {
 6923            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6924            self.quick_selection_highlight_task.take();
 6925            self.debounced_selection_highlight_task.take();
 6926            return;
 6927        };
 6928        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6929        if on_buffer_edit
 6930            || self
 6931                .quick_selection_highlight_task
 6932                .as_ref()
 6933                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6934        {
 6935            let multi_buffer_visible_start = self
 6936                .scroll_manager
 6937                .anchor()
 6938                .anchor
 6939                .to_point(&multi_buffer_snapshot);
 6940            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6941                multi_buffer_visible_start
 6942                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6943                Bias::Left,
 6944            );
 6945            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6946            self.quick_selection_highlight_task = Some((
 6947                query_range.clone(),
 6948                self.update_selection_occurrence_highlights(
 6949                    query_text.clone(),
 6950                    query_range.clone(),
 6951                    multi_buffer_visible_range,
 6952                    false,
 6953                    window,
 6954                    cx,
 6955                ),
 6956            ));
 6957        }
 6958        if on_buffer_edit
 6959            || self
 6960                .debounced_selection_highlight_task
 6961                .as_ref()
 6962                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6963        {
 6964            let multi_buffer_start = multi_buffer_snapshot
 6965                .anchor_before(0)
 6966                .to_point(&multi_buffer_snapshot);
 6967            let multi_buffer_end = multi_buffer_snapshot
 6968                .anchor_after(multi_buffer_snapshot.len())
 6969                .to_point(&multi_buffer_snapshot);
 6970            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6971            self.debounced_selection_highlight_task = Some((
 6972                query_range.clone(),
 6973                self.update_selection_occurrence_highlights(
 6974                    query_text,
 6975                    query_range,
 6976                    multi_buffer_full_range,
 6977                    true,
 6978                    window,
 6979                    cx,
 6980                ),
 6981            ));
 6982        }
 6983    }
 6984
 6985    pub fn refresh_edit_prediction(
 6986        &mut self,
 6987        debounce: bool,
 6988        user_requested: bool,
 6989        window: &mut Window,
 6990        cx: &mut Context<Self>,
 6991    ) -> Option<()> {
 6992        if DisableAiSettings::get_global(cx).disable_ai {
 6993            return None;
 6994        }
 6995
 6996        let provider = self.edit_prediction_provider()?;
 6997        let cursor = self.selections.newest_anchor().head();
 6998        let (buffer, cursor_buffer_position) =
 6999            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7000
 7001        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7002            self.discard_edit_prediction(false, cx);
 7003            return None;
 7004        }
 7005
 7006        self.update_visible_edit_prediction(window, cx);
 7007
 7008        if !user_requested
 7009            && (!self.should_show_edit_predictions()
 7010                || !self.is_focused(window)
 7011                || buffer.read(cx).is_empty())
 7012        {
 7013            self.discard_edit_prediction(false, cx);
 7014            return None;
 7015        }
 7016
 7017        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7018        Some(())
 7019    }
 7020
 7021    fn show_edit_predictions_in_menu(&self) -> bool {
 7022        match self.edit_prediction_settings {
 7023            EditPredictionSettings::Disabled => false,
 7024            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7025        }
 7026    }
 7027
 7028    pub fn edit_predictions_enabled(&self) -> bool {
 7029        match self.edit_prediction_settings {
 7030            EditPredictionSettings::Disabled => false,
 7031            EditPredictionSettings::Enabled { .. } => true,
 7032        }
 7033    }
 7034
 7035    fn edit_prediction_requires_modifier(&self) -> bool {
 7036        match self.edit_prediction_settings {
 7037            EditPredictionSettings::Disabled => false,
 7038            EditPredictionSettings::Enabled {
 7039                preview_requires_modifier,
 7040                ..
 7041            } => preview_requires_modifier,
 7042        }
 7043    }
 7044
 7045    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7046        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7047            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7048            self.discard_edit_prediction(false, cx);
 7049        } else {
 7050            let selection = self.selections.newest_anchor();
 7051            let cursor = selection.head();
 7052
 7053            if let Some((buffer, cursor_buffer_position)) =
 7054                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7055            {
 7056                self.edit_prediction_settings =
 7057                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7058            }
 7059        }
 7060    }
 7061
 7062    fn edit_prediction_settings_at_position(
 7063        &self,
 7064        buffer: &Entity<Buffer>,
 7065        buffer_position: language::Anchor,
 7066        cx: &App,
 7067    ) -> EditPredictionSettings {
 7068        if !self.mode.is_full()
 7069            || !self.show_edit_predictions_override.unwrap_or(true)
 7070            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7071        {
 7072            return EditPredictionSettings::Disabled;
 7073        }
 7074
 7075        let buffer = buffer.read(cx);
 7076
 7077        let file = buffer.file();
 7078
 7079        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7080            return EditPredictionSettings::Disabled;
 7081        };
 7082
 7083        let by_provider = matches!(
 7084            self.menu_edit_predictions_policy,
 7085            MenuEditPredictionsPolicy::ByProvider
 7086        );
 7087
 7088        let show_in_menu = by_provider
 7089            && self
 7090                .edit_prediction_provider
 7091                .as_ref()
 7092                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7093
 7094        let preview_requires_modifier =
 7095            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7096
 7097        EditPredictionSettings::Enabled {
 7098            show_in_menu,
 7099            preview_requires_modifier,
 7100        }
 7101    }
 7102
 7103    fn should_show_edit_predictions(&self) -> bool {
 7104        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7105    }
 7106
 7107    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7108        matches!(
 7109            self.edit_prediction_preview,
 7110            EditPredictionPreview::Active { .. }
 7111        )
 7112    }
 7113
 7114    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7115        let cursor = self.selections.newest_anchor().head();
 7116        if let Some((buffer, cursor_position)) =
 7117            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7118        {
 7119            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7120        } else {
 7121            false
 7122        }
 7123    }
 7124
 7125    pub fn supports_minimap(&self, cx: &App) -> bool {
 7126        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7127    }
 7128
 7129    fn edit_predictions_enabled_in_buffer(
 7130        &self,
 7131        buffer: &Entity<Buffer>,
 7132        buffer_position: language::Anchor,
 7133        cx: &App,
 7134    ) -> bool {
 7135        maybe!({
 7136            if self.read_only(cx) {
 7137                return Some(false);
 7138            }
 7139            let provider = self.edit_prediction_provider()?;
 7140            if !provider.is_enabled(buffer, buffer_position, cx) {
 7141                return Some(false);
 7142            }
 7143            let buffer = buffer.read(cx);
 7144            let Some(file) = buffer.file() else {
 7145                return Some(true);
 7146            };
 7147            let settings = all_language_settings(Some(file), cx);
 7148            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7149        })
 7150        .unwrap_or(false)
 7151    }
 7152
 7153    fn cycle_edit_prediction(
 7154        &mut self,
 7155        direction: Direction,
 7156        window: &mut Window,
 7157        cx: &mut Context<Self>,
 7158    ) -> Option<()> {
 7159        let provider = self.edit_prediction_provider()?;
 7160        let cursor = self.selections.newest_anchor().head();
 7161        let (buffer, cursor_buffer_position) =
 7162            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7163        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7164            return None;
 7165        }
 7166
 7167        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7168        self.update_visible_edit_prediction(window, cx);
 7169
 7170        Some(())
 7171    }
 7172
 7173    pub fn show_edit_prediction(
 7174        &mut self,
 7175        _: &ShowEditPrediction,
 7176        window: &mut Window,
 7177        cx: &mut Context<Self>,
 7178    ) {
 7179        if !self.has_active_edit_prediction() {
 7180            self.refresh_edit_prediction(false, true, window, cx);
 7181            return;
 7182        }
 7183
 7184        self.update_visible_edit_prediction(window, cx);
 7185    }
 7186
 7187    pub fn display_cursor_names(
 7188        &mut self,
 7189        _: &DisplayCursorNames,
 7190        window: &mut Window,
 7191        cx: &mut Context<Self>,
 7192    ) {
 7193        self.show_cursor_names(window, cx);
 7194    }
 7195
 7196    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7197        self.show_cursor_names = true;
 7198        cx.notify();
 7199        cx.spawn_in(window, async move |this, cx| {
 7200            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7201            this.update(cx, |this, cx| {
 7202                this.show_cursor_names = false;
 7203                cx.notify()
 7204            })
 7205            .ok()
 7206        })
 7207        .detach();
 7208    }
 7209
 7210    pub fn next_edit_prediction(
 7211        &mut self,
 7212        _: &NextEditPrediction,
 7213        window: &mut Window,
 7214        cx: &mut Context<Self>,
 7215    ) {
 7216        if self.has_active_edit_prediction() {
 7217            self.cycle_edit_prediction(Direction::Next, window, cx);
 7218        } else {
 7219            let is_copilot_disabled = self
 7220                .refresh_edit_prediction(false, true, window, cx)
 7221                .is_none();
 7222            if is_copilot_disabled {
 7223                cx.propagate();
 7224            }
 7225        }
 7226    }
 7227
 7228    pub fn previous_edit_prediction(
 7229        &mut self,
 7230        _: &PreviousEditPrediction,
 7231        window: &mut Window,
 7232        cx: &mut Context<Self>,
 7233    ) {
 7234        if self.has_active_edit_prediction() {
 7235            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7236        } else {
 7237            let is_copilot_disabled = self
 7238                .refresh_edit_prediction(false, true, window, cx)
 7239                .is_none();
 7240            if is_copilot_disabled {
 7241                cx.propagate();
 7242            }
 7243        }
 7244    }
 7245
 7246    pub fn accept_edit_prediction(
 7247        &mut self,
 7248        _: &AcceptEditPrediction,
 7249        window: &mut Window,
 7250        cx: &mut Context<Self>,
 7251    ) {
 7252        if self.show_edit_predictions_in_menu() {
 7253            self.hide_context_menu(window, cx);
 7254        }
 7255
 7256        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7257            return;
 7258        };
 7259
 7260        match &active_edit_prediction.completion {
 7261            EditPrediction::MoveWithin { target, .. } => {
 7262                let target = *target;
 7263
 7264                if let Some(position_map) = &self.last_position_map {
 7265                    if position_map
 7266                        .visible_row_range
 7267                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7268                        || !self.edit_prediction_requires_modifier()
 7269                    {
 7270                        self.unfold_ranges(&[target..target], true, false, cx);
 7271                        // Note that this is also done in vim's handler of the Tab action.
 7272                        self.change_selections(
 7273                            SelectionEffects::scroll(Autoscroll::newest()),
 7274                            window,
 7275                            cx,
 7276                            |selections| {
 7277                                selections.select_anchor_ranges([target..target]);
 7278                            },
 7279                        );
 7280                        self.clear_row_highlights::<EditPredictionPreview>();
 7281
 7282                        self.edit_prediction_preview
 7283                            .set_previous_scroll_position(None);
 7284                    } else {
 7285                        self.edit_prediction_preview
 7286                            .set_previous_scroll_position(Some(
 7287                                position_map.snapshot.scroll_anchor,
 7288                            ));
 7289
 7290                        self.highlight_rows::<EditPredictionPreview>(
 7291                            target..target,
 7292                            cx.theme().colors().editor_highlighted_line_background,
 7293                            RowHighlightOptions {
 7294                                autoscroll: true,
 7295                                ..Default::default()
 7296                            },
 7297                            cx,
 7298                        );
 7299                        self.request_autoscroll(Autoscroll::fit(), cx);
 7300                    }
 7301                }
 7302            }
 7303            EditPrediction::MoveOutside { snapshot, target } => {
 7304                if let Some(workspace) = self.workspace() {
 7305                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7306                        .detach_and_log_err(cx);
 7307                }
 7308            }
 7309            EditPrediction::Edit { edits, .. } => {
 7310                self.report_edit_prediction_event(
 7311                    active_edit_prediction.completion_id.clone(),
 7312                    true,
 7313                    cx,
 7314                );
 7315
 7316                if let Some(provider) = self.edit_prediction_provider() {
 7317                    provider.accept(cx);
 7318                }
 7319
 7320                // Store the transaction ID and selections before applying the edit
 7321                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7322
 7323                let snapshot = self.buffer.read(cx).snapshot(cx);
 7324                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7325
 7326                self.buffer.update(cx, |buffer, cx| {
 7327                    buffer.edit(edits.iter().cloned(), None, cx)
 7328                });
 7329
 7330                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7331                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7332                });
 7333
 7334                let selections = self.selections.disjoint_anchors_arc();
 7335                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7336                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7337                    if has_new_transaction {
 7338                        self.selection_history
 7339                            .insert_transaction(transaction_id_now, selections);
 7340                    }
 7341                }
 7342
 7343                self.update_visible_edit_prediction(window, cx);
 7344                if self.active_edit_prediction.is_none() {
 7345                    self.refresh_edit_prediction(true, true, window, cx);
 7346                }
 7347
 7348                cx.notify();
 7349            }
 7350        }
 7351
 7352        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7353    }
 7354
 7355    pub fn accept_partial_edit_prediction(
 7356        &mut self,
 7357        _: &AcceptPartialEditPrediction,
 7358        window: &mut Window,
 7359        cx: &mut Context<Self>,
 7360    ) {
 7361        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7362            return;
 7363        };
 7364        if self.selections.count() != 1 {
 7365            return;
 7366        }
 7367
 7368        match &active_edit_prediction.completion {
 7369            EditPrediction::MoveWithin { target, .. } => {
 7370                let target = *target;
 7371                self.change_selections(
 7372                    SelectionEffects::scroll(Autoscroll::newest()),
 7373                    window,
 7374                    cx,
 7375                    |selections| {
 7376                        selections.select_anchor_ranges([target..target]);
 7377                    },
 7378                );
 7379            }
 7380            EditPrediction::MoveOutside { snapshot, target } => {
 7381                if let Some(workspace) = self.workspace() {
 7382                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7383                        .detach_and_log_err(cx);
 7384                }
 7385            }
 7386            EditPrediction::Edit { edits, .. } => {
 7387                self.report_edit_prediction_event(
 7388                    active_edit_prediction.completion_id.clone(),
 7389                    true,
 7390                    cx,
 7391                );
 7392
 7393                // Find an insertion that starts at the cursor position.
 7394                let snapshot = self.buffer.read(cx).snapshot(cx);
 7395                let cursor_offset = self
 7396                    .selections
 7397                    .newest::<usize>(&self.display_snapshot(cx))
 7398                    .head();
 7399                let insertion = edits.iter().find_map(|(range, text)| {
 7400                    let range = range.to_offset(&snapshot);
 7401                    if range.is_empty() && range.start == cursor_offset {
 7402                        Some(text)
 7403                    } else {
 7404                        None
 7405                    }
 7406                });
 7407
 7408                if let Some(text) = insertion {
 7409                    let mut partial_completion = text
 7410                        .chars()
 7411                        .by_ref()
 7412                        .take_while(|c| c.is_alphabetic())
 7413                        .collect::<String>();
 7414                    if partial_completion.is_empty() {
 7415                        partial_completion = text
 7416                            .chars()
 7417                            .by_ref()
 7418                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7419                            .collect::<String>();
 7420                    }
 7421
 7422                    cx.emit(EditorEvent::InputHandled {
 7423                        utf16_range_to_replace: None,
 7424                        text: partial_completion.clone().into(),
 7425                    });
 7426
 7427                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7428
 7429                    self.refresh_edit_prediction(true, true, window, cx);
 7430                    cx.notify();
 7431                } else {
 7432                    self.accept_edit_prediction(&Default::default(), window, cx);
 7433                }
 7434            }
 7435        }
 7436    }
 7437
 7438    fn discard_edit_prediction(
 7439        &mut self,
 7440        should_report_edit_prediction_event: bool,
 7441        cx: &mut Context<Self>,
 7442    ) -> bool {
 7443        if should_report_edit_prediction_event {
 7444            let completion_id = self
 7445                .active_edit_prediction
 7446                .as_ref()
 7447                .and_then(|active_completion| active_completion.completion_id.clone());
 7448
 7449            self.report_edit_prediction_event(completion_id, false, cx);
 7450        }
 7451
 7452        if let Some(provider) = self.edit_prediction_provider() {
 7453            provider.discard(cx);
 7454        }
 7455
 7456        self.take_active_edit_prediction(cx)
 7457    }
 7458
 7459    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7460        let Some(provider) = self.edit_prediction_provider() else {
 7461            return;
 7462        };
 7463
 7464        let Some((_, buffer, _)) = self
 7465            .buffer
 7466            .read(cx)
 7467            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7468        else {
 7469            return;
 7470        };
 7471
 7472        let extension = buffer
 7473            .read(cx)
 7474            .file()
 7475            .and_then(|file| Some(file.path().extension()?.to_string()));
 7476
 7477        let event_type = match accepted {
 7478            true => "Edit Prediction Accepted",
 7479            false => "Edit Prediction Discarded",
 7480        };
 7481        telemetry::event!(
 7482            event_type,
 7483            provider = provider.name(),
 7484            prediction_id = id,
 7485            suggestion_accepted = accepted,
 7486            file_extension = extension,
 7487        );
 7488    }
 7489
 7490    fn open_editor_at_anchor(
 7491        snapshot: &language::BufferSnapshot,
 7492        target: language::Anchor,
 7493        workspace: &Entity<Workspace>,
 7494        window: &mut Window,
 7495        cx: &mut App,
 7496    ) -> Task<Result<()>> {
 7497        workspace.update(cx, |workspace, cx| {
 7498            let path = snapshot.file().map(|file| file.full_path(cx));
 7499            let Some(path) =
 7500                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7501            else {
 7502                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7503            };
 7504            let target = text::ToPoint::to_point(&target, snapshot);
 7505            let item = workspace.open_path(path, None, true, window, cx);
 7506            window.spawn(cx, async move |cx| {
 7507                let Some(editor) = item.await?.downcast::<Editor>() else {
 7508                    return Ok(());
 7509                };
 7510                editor
 7511                    .update_in(cx, |editor, window, cx| {
 7512                        editor.go_to_singleton_buffer_point(target, window, cx);
 7513                    })
 7514                    .ok();
 7515                anyhow::Ok(())
 7516            })
 7517        })
 7518    }
 7519
 7520    pub fn has_active_edit_prediction(&self) -> bool {
 7521        self.active_edit_prediction.is_some()
 7522    }
 7523
 7524    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7525        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7526            return false;
 7527        };
 7528
 7529        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7530        self.clear_highlights::<EditPredictionHighlight>(cx);
 7531        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7532        true
 7533    }
 7534
 7535    /// Returns true when we're displaying the edit prediction popover below the cursor
 7536    /// like we are not previewing and the LSP autocomplete menu is visible
 7537    /// or we are in `when_holding_modifier` mode.
 7538    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7539        if self.edit_prediction_preview_is_active()
 7540            || !self.show_edit_predictions_in_menu()
 7541            || !self.edit_predictions_enabled()
 7542        {
 7543            return false;
 7544        }
 7545
 7546        if self.has_visible_completions_menu() {
 7547            return true;
 7548        }
 7549
 7550        has_completion && self.edit_prediction_requires_modifier()
 7551    }
 7552
 7553    fn handle_modifiers_changed(
 7554        &mut self,
 7555        modifiers: Modifiers,
 7556        position_map: &PositionMap,
 7557        window: &mut Window,
 7558        cx: &mut Context<Self>,
 7559    ) {
 7560        if self.show_edit_predictions_in_menu() {
 7561            self.update_edit_prediction_preview(&modifiers, window, cx);
 7562        }
 7563
 7564        self.update_selection_mode(&modifiers, position_map, window, cx);
 7565
 7566        let mouse_position = window.mouse_position();
 7567        if !position_map.text_hitbox.is_hovered(window) {
 7568            return;
 7569        }
 7570
 7571        self.update_hovered_link(
 7572            position_map.point_for_position(mouse_position),
 7573            &position_map.snapshot,
 7574            modifiers,
 7575            window,
 7576            cx,
 7577        )
 7578    }
 7579
 7580    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7581        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7582        if invert {
 7583            match multi_cursor_setting {
 7584                MultiCursorModifier::Alt => modifiers.alt,
 7585                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7586            }
 7587        } else {
 7588            match multi_cursor_setting {
 7589                MultiCursorModifier::Alt => modifiers.secondary(),
 7590                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7591            }
 7592        }
 7593    }
 7594
 7595    fn columnar_selection_mode(
 7596        modifiers: &Modifiers,
 7597        cx: &mut Context<Self>,
 7598    ) -> Option<ColumnarMode> {
 7599        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7600            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7601                Some(ColumnarMode::FromMouse)
 7602            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7603                Some(ColumnarMode::FromSelection)
 7604            } else {
 7605                None
 7606            }
 7607        } else {
 7608            None
 7609        }
 7610    }
 7611
 7612    fn update_selection_mode(
 7613        &mut self,
 7614        modifiers: &Modifiers,
 7615        position_map: &PositionMap,
 7616        window: &mut Window,
 7617        cx: &mut Context<Self>,
 7618    ) {
 7619        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7620            return;
 7621        };
 7622        if self.selections.pending_anchor().is_none() {
 7623            return;
 7624        }
 7625
 7626        let mouse_position = window.mouse_position();
 7627        let point_for_position = position_map.point_for_position(mouse_position);
 7628        let position = point_for_position.previous_valid;
 7629
 7630        self.select(
 7631            SelectPhase::BeginColumnar {
 7632                position,
 7633                reset: false,
 7634                mode,
 7635                goal_column: point_for_position.exact_unclipped.column(),
 7636            },
 7637            window,
 7638            cx,
 7639        );
 7640    }
 7641
 7642    fn update_edit_prediction_preview(
 7643        &mut self,
 7644        modifiers: &Modifiers,
 7645        window: &mut Window,
 7646        cx: &mut Context<Self>,
 7647    ) {
 7648        let mut modifiers_held = false;
 7649        if let Some(accept_keystroke) = self
 7650            .accept_edit_prediction_keybind(false, window, cx)
 7651            .keystroke()
 7652        {
 7653            modifiers_held = modifiers_held
 7654                || (accept_keystroke.modifiers() == modifiers
 7655                    && accept_keystroke.modifiers().modified());
 7656        };
 7657        if let Some(accept_partial_keystroke) = self
 7658            .accept_edit_prediction_keybind(true, window, cx)
 7659            .keystroke()
 7660        {
 7661            modifiers_held = modifiers_held
 7662                || (accept_partial_keystroke.modifiers() == modifiers
 7663                    && accept_partial_keystroke.modifiers().modified());
 7664        }
 7665
 7666        if modifiers_held {
 7667            if matches!(
 7668                self.edit_prediction_preview,
 7669                EditPredictionPreview::Inactive { .. }
 7670            ) {
 7671                self.edit_prediction_preview = EditPredictionPreview::Active {
 7672                    previous_scroll_position: None,
 7673                    since: Instant::now(),
 7674                };
 7675
 7676                self.update_visible_edit_prediction(window, cx);
 7677                cx.notify();
 7678            }
 7679        } else if let EditPredictionPreview::Active {
 7680            previous_scroll_position,
 7681            since,
 7682        } = self.edit_prediction_preview
 7683        {
 7684            if let (Some(previous_scroll_position), Some(position_map)) =
 7685                (previous_scroll_position, self.last_position_map.as_ref())
 7686            {
 7687                self.set_scroll_position(
 7688                    previous_scroll_position
 7689                        .scroll_position(&position_map.snapshot.display_snapshot),
 7690                    window,
 7691                    cx,
 7692                );
 7693            }
 7694
 7695            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7696                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7697            };
 7698            self.clear_row_highlights::<EditPredictionPreview>();
 7699            self.update_visible_edit_prediction(window, cx);
 7700            cx.notify();
 7701        }
 7702    }
 7703
 7704    fn update_visible_edit_prediction(
 7705        &mut self,
 7706        _window: &mut Window,
 7707        cx: &mut Context<Self>,
 7708    ) -> Option<()> {
 7709        if DisableAiSettings::get_global(cx).disable_ai {
 7710            return None;
 7711        }
 7712
 7713        if self.ime_transaction.is_some() {
 7714            self.discard_edit_prediction(false, cx);
 7715            return None;
 7716        }
 7717
 7718        let selection = self.selections.newest_anchor();
 7719        let cursor = selection.head();
 7720        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7721        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7722        let excerpt_id = cursor.excerpt_id;
 7723
 7724        let show_in_menu = self.show_edit_predictions_in_menu();
 7725        let completions_menu_has_precedence = !show_in_menu
 7726            && (self.context_menu.borrow().is_some()
 7727                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7728
 7729        if completions_menu_has_precedence
 7730            || !offset_selection.is_empty()
 7731            || self
 7732                .active_edit_prediction
 7733                .as_ref()
 7734                .is_some_and(|completion| {
 7735                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7736                        return false;
 7737                    };
 7738                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7739                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7740                    !invalidation_range.contains(&offset_selection.head())
 7741                })
 7742        {
 7743            self.discard_edit_prediction(false, cx);
 7744            return None;
 7745        }
 7746
 7747        self.take_active_edit_prediction(cx);
 7748        let Some(provider) = self.edit_prediction_provider() else {
 7749            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7750            return None;
 7751        };
 7752
 7753        let (buffer, cursor_buffer_position) =
 7754            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7755
 7756        self.edit_prediction_settings =
 7757            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7758
 7759        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7760
 7761        if self.edit_prediction_indent_conflict {
 7762            let cursor_point = cursor.to_point(&multibuffer);
 7763
 7764            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7765
 7766            if let Some((_, indent)) = indents.iter().next()
 7767                && indent.len == cursor_point.column
 7768            {
 7769                self.edit_prediction_indent_conflict = false;
 7770            }
 7771        }
 7772
 7773        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7774
 7775        let (completion_id, edits, edit_preview) = match edit_prediction {
 7776            edit_prediction::EditPrediction::Local {
 7777                id,
 7778                edits,
 7779                edit_preview,
 7780            } => (id, edits, edit_preview),
 7781            edit_prediction::EditPrediction::Jump {
 7782                id,
 7783                snapshot,
 7784                target,
 7785            } => {
 7786                self.stale_edit_prediction_in_menu = None;
 7787                self.active_edit_prediction = Some(EditPredictionState {
 7788                    inlay_ids: vec![],
 7789                    completion: EditPrediction::MoveOutside { snapshot, target },
 7790                    completion_id: id,
 7791                    invalidation_range: None,
 7792                });
 7793                cx.notify();
 7794                return Some(());
 7795            }
 7796        };
 7797
 7798        let edits = edits
 7799            .into_iter()
 7800            .flat_map(|(range, new_text)| {
 7801                Some((
 7802                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7803                    new_text,
 7804                ))
 7805            })
 7806            .collect::<Vec<_>>();
 7807        if edits.is_empty() {
 7808            return None;
 7809        }
 7810
 7811        let first_edit_start = edits.first().unwrap().0.start;
 7812        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7813        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7814
 7815        let last_edit_end = edits.last().unwrap().0.end;
 7816        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7817        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7818
 7819        let cursor_row = cursor.to_point(&multibuffer).row;
 7820
 7821        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7822
 7823        let mut inlay_ids = Vec::new();
 7824        let invalidation_row_range;
 7825        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7826            Some(cursor_row..edit_end_row)
 7827        } else if cursor_row > edit_end_row {
 7828            Some(edit_start_row..cursor_row)
 7829        } else {
 7830            None
 7831        };
 7832        let supports_jump = self
 7833            .edit_prediction_provider
 7834            .as_ref()
 7835            .map(|provider| provider.provider.supports_jump_to_edit())
 7836            .unwrap_or(true);
 7837
 7838        let is_move = supports_jump
 7839            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7840        let completion = if is_move {
 7841            invalidation_row_range =
 7842                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7843            let target = first_edit_start;
 7844            EditPrediction::MoveWithin { target, snapshot }
 7845        } else {
 7846            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7847                && !self.edit_predictions_hidden_for_vim_mode;
 7848
 7849            if show_completions_in_buffer {
 7850                if edits
 7851                    .iter()
 7852                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7853                {
 7854                    let mut inlays = Vec::new();
 7855                    for (range, new_text) in &edits {
 7856                        let inlay = Inlay::edit_prediction(
 7857                            post_inc(&mut self.next_inlay_id),
 7858                            range.start,
 7859                            new_text.as_str(),
 7860                        );
 7861                        inlay_ids.push(inlay.id);
 7862                        inlays.push(inlay);
 7863                    }
 7864
 7865                    self.splice_inlays(&[], inlays, cx);
 7866                } else {
 7867                    let background_color = cx.theme().status().deleted_background;
 7868                    self.highlight_text::<EditPredictionHighlight>(
 7869                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7870                        HighlightStyle {
 7871                            background_color: Some(background_color),
 7872                            ..Default::default()
 7873                        },
 7874                        cx,
 7875                    );
 7876                }
 7877            }
 7878
 7879            invalidation_row_range = edit_start_row..edit_end_row;
 7880
 7881            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7882                if provider.show_tab_accept_marker() {
 7883                    EditDisplayMode::TabAccept
 7884                } else {
 7885                    EditDisplayMode::Inline
 7886                }
 7887            } else {
 7888                EditDisplayMode::DiffPopover
 7889            };
 7890
 7891            EditPrediction::Edit {
 7892                edits,
 7893                edit_preview,
 7894                display_mode,
 7895                snapshot,
 7896            }
 7897        };
 7898
 7899        let invalidation_range = multibuffer
 7900            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7901            ..multibuffer.anchor_after(Point::new(
 7902                invalidation_row_range.end,
 7903                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7904            ));
 7905
 7906        self.stale_edit_prediction_in_menu = None;
 7907        self.active_edit_prediction = Some(EditPredictionState {
 7908            inlay_ids,
 7909            completion,
 7910            completion_id,
 7911            invalidation_range: Some(invalidation_range),
 7912        });
 7913
 7914        cx.notify();
 7915
 7916        Some(())
 7917    }
 7918
 7919    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7920        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7921    }
 7922
 7923    fn clear_tasks(&mut self) {
 7924        self.tasks.clear()
 7925    }
 7926
 7927    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7928        if self.tasks.insert(key, value).is_some() {
 7929            // This case should hopefully be rare, but just in case...
 7930            log::error!(
 7931                "multiple different run targets found on a single line, only the last target will be rendered"
 7932            )
 7933        }
 7934    }
 7935
 7936    /// Get all display points of breakpoints that will be rendered within editor
 7937    ///
 7938    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7939    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7940    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7941    fn active_breakpoints(
 7942        &self,
 7943        range: Range<DisplayRow>,
 7944        window: &mut Window,
 7945        cx: &mut Context<Self>,
 7946    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7947        let mut breakpoint_display_points = HashMap::default();
 7948
 7949        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7950            return breakpoint_display_points;
 7951        };
 7952
 7953        let snapshot = self.snapshot(window, cx);
 7954
 7955        let multi_buffer_snapshot = snapshot.display_snapshot.buffer_snapshot();
 7956        let Some(project) = self.project() else {
 7957            return breakpoint_display_points;
 7958        };
 7959
 7960        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7961            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7962
 7963        for (buffer_snapshot, range, excerpt_id) in
 7964            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7965        {
 7966            let Some(buffer) = project
 7967                .read(cx)
 7968                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7969            else {
 7970                continue;
 7971            };
 7972            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7973                &buffer,
 7974                Some(
 7975                    buffer_snapshot.anchor_before(range.start)
 7976                        ..buffer_snapshot.anchor_after(range.end),
 7977                ),
 7978                buffer_snapshot,
 7979                cx,
 7980            );
 7981            for (breakpoint, state) in breakpoints {
 7982                let multi_buffer_anchor =
 7983                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7984                let position = multi_buffer_anchor
 7985                    .to_point(multi_buffer_snapshot)
 7986                    .to_display_point(&snapshot);
 7987
 7988                breakpoint_display_points.insert(
 7989                    position.row(),
 7990                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7991                );
 7992            }
 7993        }
 7994
 7995        breakpoint_display_points
 7996    }
 7997
 7998    fn breakpoint_context_menu(
 7999        &self,
 8000        anchor: Anchor,
 8001        window: &mut Window,
 8002        cx: &mut Context<Self>,
 8003    ) -> Entity<ui::ContextMenu> {
 8004        let weak_editor = cx.weak_entity();
 8005        let focus_handle = self.focus_handle(cx);
 8006
 8007        let row = self
 8008            .buffer
 8009            .read(cx)
 8010            .snapshot(cx)
 8011            .summary_for_anchor::<Point>(&anchor)
 8012            .row;
 8013
 8014        let breakpoint = self
 8015            .breakpoint_at_row(row, window, cx)
 8016            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8017
 8018        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8019            "Edit Log Breakpoint"
 8020        } else {
 8021            "Set Log Breakpoint"
 8022        };
 8023
 8024        let condition_breakpoint_msg = if breakpoint
 8025            .as_ref()
 8026            .is_some_and(|bp| bp.1.condition.is_some())
 8027        {
 8028            "Edit Condition Breakpoint"
 8029        } else {
 8030            "Set Condition Breakpoint"
 8031        };
 8032
 8033        let hit_condition_breakpoint_msg = if breakpoint
 8034            .as_ref()
 8035            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8036        {
 8037            "Edit Hit Condition Breakpoint"
 8038        } else {
 8039            "Set Hit Condition Breakpoint"
 8040        };
 8041
 8042        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8043            "Unset Breakpoint"
 8044        } else {
 8045            "Set Breakpoint"
 8046        };
 8047
 8048        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8049
 8050        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8051            BreakpointState::Enabled => Some("Disable"),
 8052            BreakpointState::Disabled => Some("Enable"),
 8053        });
 8054
 8055        let (anchor, breakpoint) =
 8056            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8057
 8058        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8059            menu.on_blur_subscription(Subscription::new(|| {}))
 8060                .context(focus_handle)
 8061                .when(run_to_cursor, |this| {
 8062                    let weak_editor = weak_editor.clone();
 8063                    this.entry("Run to cursor", None, move |window, cx| {
 8064                        weak_editor
 8065                            .update(cx, |editor, cx| {
 8066                                editor.change_selections(
 8067                                    SelectionEffects::no_scroll(),
 8068                                    window,
 8069                                    cx,
 8070                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8071                                );
 8072                            })
 8073                            .ok();
 8074
 8075                        window.dispatch_action(Box::new(RunToCursor), cx);
 8076                    })
 8077                    .separator()
 8078                })
 8079                .when_some(toggle_state_msg, |this, msg| {
 8080                    this.entry(msg, None, {
 8081                        let weak_editor = weak_editor.clone();
 8082                        let breakpoint = breakpoint.clone();
 8083                        move |_window, cx| {
 8084                            weak_editor
 8085                                .update(cx, |this, cx| {
 8086                                    this.edit_breakpoint_at_anchor(
 8087                                        anchor,
 8088                                        breakpoint.as_ref().clone(),
 8089                                        BreakpointEditAction::InvertState,
 8090                                        cx,
 8091                                    );
 8092                                })
 8093                                .log_err();
 8094                        }
 8095                    })
 8096                })
 8097                .entry(set_breakpoint_msg, None, {
 8098                    let weak_editor = weak_editor.clone();
 8099                    let breakpoint = breakpoint.clone();
 8100                    move |_window, cx| {
 8101                        weak_editor
 8102                            .update(cx, |this, cx| {
 8103                                this.edit_breakpoint_at_anchor(
 8104                                    anchor,
 8105                                    breakpoint.as_ref().clone(),
 8106                                    BreakpointEditAction::Toggle,
 8107                                    cx,
 8108                                );
 8109                            })
 8110                            .log_err();
 8111                    }
 8112                })
 8113                .entry(log_breakpoint_msg, None, {
 8114                    let breakpoint = breakpoint.clone();
 8115                    let weak_editor = weak_editor.clone();
 8116                    move |window, cx| {
 8117                        weak_editor
 8118                            .update(cx, |this, cx| {
 8119                                this.add_edit_breakpoint_block(
 8120                                    anchor,
 8121                                    breakpoint.as_ref(),
 8122                                    BreakpointPromptEditAction::Log,
 8123                                    window,
 8124                                    cx,
 8125                                );
 8126                            })
 8127                            .log_err();
 8128                    }
 8129                })
 8130                .entry(condition_breakpoint_msg, None, {
 8131                    let breakpoint = breakpoint.clone();
 8132                    let weak_editor = weak_editor.clone();
 8133                    move |window, cx| {
 8134                        weak_editor
 8135                            .update(cx, |this, cx| {
 8136                                this.add_edit_breakpoint_block(
 8137                                    anchor,
 8138                                    breakpoint.as_ref(),
 8139                                    BreakpointPromptEditAction::Condition,
 8140                                    window,
 8141                                    cx,
 8142                                );
 8143                            })
 8144                            .log_err();
 8145                    }
 8146                })
 8147                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8148                    weak_editor
 8149                        .update(cx, |this, cx| {
 8150                            this.add_edit_breakpoint_block(
 8151                                anchor,
 8152                                breakpoint.as_ref(),
 8153                                BreakpointPromptEditAction::HitCondition,
 8154                                window,
 8155                                cx,
 8156                            );
 8157                        })
 8158                        .log_err();
 8159                })
 8160        })
 8161    }
 8162
 8163    fn render_breakpoint(
 8164        &self,
 8165        position: Anchor,
 8166        row: DisplayRow,
 8167        breakpoint: &Breakpoint,
 8168        state: Option<BreakpointSessionState>,
 8169        cx: &mut Context<Self>,
 8170    ) -> IconButton {
 8171        let is_rejected = state.is_some_and(|s| !s.verified);
 8172        // Is it a breakpoint that shows up when hovering over gutter?
 8173        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8174            (false, false),
 8175            |PhantomBreakpointIndicator {
 8176                 is_active,
 8177                 display_row,
 8178                 collides_with_existing_breakpoint,
 8179             }| {
 8180                (
 8181                    is_active && display_row == row,
 8182                    collides_with_existing_breakpoint,
 8183                )
 8184            },
 8185        );
 8186
 8187        let (color, icon) = {
 8188            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8189                (false, false) => ui::IconName::DebugBreakpoint,
 8190                (true, false) => ui::IconName::DebugLogBreakpoint,
 8191                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8192                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8193            };
 8194
 8195            let color = if is_phantom {
 8196                Color::Hint
 8197            } else if is_rejected {
 8198                Color::Disabled
 8199            } else {
 8200                Color::Debugger
 8201            };
 8202
 8203            (color, icon)
 8204        };
 8205
 8206        let breakpoint = Arc::from(breakpoint.clone());
 8207
 8208        let alt_as_text = gpui::Keystroke {
 8209            modifiers: Modifiers::secondary_key(),
 8210            ..Default::default()
 8211        };
 8212        let primary_action_text = if breakpoint.is_disabled() {
 8213            "Enable breakpoint"
 8214        } else if is_phantom && !collides_with_existing {
 8215            "Set breakpoint"
 8216        } else {
 8217            "Unset breakpoint"
 8218        };
 8219        let focus_handle = self.focus_handle.clone();
 8220
 8221        let meta = if is_rejected {
 8222            SharedString::from("No executable code is associated with this line.")
 8223        } else if collides_with_existing && !breakpoint.is_disabled() {
 8224            SharedString::from(format!(
 8225                "{alt_as_text}-click to disable,\nright-click for more options."
 8226            ))
 8227        } else {
 8228            SharedString::from("Right-click for more options.")
 8229        };
 8230        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8231            .icon_size(IconSize::XSmall)
 8232            .size(ui::ButtonSize::None)
 8233            .when(is_rejected, |this| {
 8234                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8235            })
 8236            .icon_color(color)
 8237            .style(ButtonStyle::Transparent)
 8238            .on_click(cx.listener({
 8239                move |editor, event: &ClickEvent, window, cx| {
 8240                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8241                        BreakpointEditAction::InvertState
 8242                    } else {
 8243                        BreakpointEditAction::Toggle
 8244                    };
 8245
 8246                    window.focus(&editor.focus_handle(cx));
 8247                    editor.edit_breakpoint_at_anchor(
 8248                        position,
 8249                        breakpoint.as_ref().clone(),
 8250                        edit_action,
 8251                        cx,
 8252                    );
 8253                }
 8254            }))
 8255            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8256                editor.set_breakpoint_context_menu(
 8257                    row,
 8258                    Some(position),
 8259                    event.position(),
 8260                    window,
 8261                    cx,
 8262                );
 8263            }))
 8264            .tooltip(move |_window, cx| {
 8265                Tooltip::with_meta_in(
 8266                    primary_action_text,
 8267                    Some(&ToggleBreakpoint),
 8268                    meta.clone(),
 8269                    &focus_handle,
 8270                    cx,
 8271                )
 8272            })
 8273    }
 8274
 8275    fn build_tasks_context(
 8276        project: &Entity<Project>,
 8277        buffer: &Entity<Buffer>,
 8278        buffer_row: u32,
 8279        tasks: &Arc<RunnableTasks>,
 8280        cx: &mut Context<Self>,
 8281    ) -> Task<Option<task::TaskContext>> {
 8282        let position = Point::new(buffer_row, tasks.column);
 8283        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8284        let location = Location {
 8285            buffer: buffer.clone(),
 8286            range: range_start..range_start,
 8287        };
 8288        // Fill in the environmental variables from the tree-sitter captures
 8289        let mut captured_task_variables = TaskVariables::default();
 8290        for (capture_name, value) in tasks.extra_variables.clone() {
 8291            captured_task_variables.insert(
 8292                task::VariableName::Custom(capture_name.into()),
 8293                value.clone(),
 8294            );
 8295        }
 8296        project.update(cx, |project, cx| {
 8297            project.task_store().update(cx, |task_store, cx| {
 8298                task_store.task_context_for_location(captured_task_variables, location, cx)
 8299            })
 8300        })
 8301    }
 8302
 8303    pub fn spawn_nearest_task(
 8304        &mut self,
 8305        action: &SpawnNearestTask,
 8306        window: &mut Window,
 8307        cx: &mut Context<Self>,
 8308    ) {
 8309        let Some((workspace, _)) = self.workspace.clone() else {
 8310            return;
 8311        };
 8312        let Some(project) = self.project.clone() else {
 8313            return;
 8314        };
 8315
 8316        // Try to find a closest, enclosing node using tree-sitter that has a task
 8317        let Some((buffer, buffer_row, tasks)) = self
 8318            .find_enclosing_node_task(cx)
 8319            // Or find the task that's closest in row-distance.
 8320            .or_else(|| self.find_closest_task(cx))
 8321        else {
 8322            return;
 8323        };
 8324
 8325        let reveal_strategy = action.reveal;
 8326        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8327        cx.spawn_in(window, async move |_, cx| {
 8328            let context = task_context.await?;
 8329            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8330
 8331            let resolved = &mut resolved_task.resolved;
 8332            resolved.reveal = reveal_strategy;
 8333
 8334            workspace
 8335                .update_in(cx, |workspace, window, cx| {
 8336                    workspace.schedule_resolved_task(
 8337                        task_source_kind,
 8338                        resolved_task,
 8339                        false,
 8340                        window,
 8341                        cx,
 8342                    );
 8343                })
 8344                .ok()
 8345        })
 8346        .detach();
 8347    }
 8348
 8349    fn find_closest_task(
 8350        &mut self,
 8351        cx: &mut Context<Self>,
 8352    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8353        let cursor_row = self
 8354            .selections
 8355            .newest_adjusted(&self.display_snapshot(cx))
 8356            .head()
 8357            .row;
 8358
 8359        let ((buffer_id, row), tasks) = self
 8360            .tasks
 8361            .iter()
 8362            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8363
 8364        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8365        let tasks = Arc::new(tasks.to_owned());
 8366        Some((buffer, *row, tasks))
 8367    }
 8368
 8369    fn find_enclosing_node_task(
 8370        &mut self,
 8371        cx: &mut Context<Self>,
 8372    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8373        let snapshot = self.buffer.read(cx).snapshot(cx);
 8374        let offset = self
 8375            .selections
 8376            .newest::<usize>(&self.display_snapshot(cx))
 8377            .head();
 8378        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8379        let buffer_id = excerpt.buffer().remote_id();
 8380
 8381        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8382        let mut cursor = layer.node().walk();
 8383
 8384        while cursor.goto_first_child_for_byte(offset).is_some() {
 8385            if cursor.node().end_byte() == offset {
 8386                cursor.goto_next_sibling();
 8387            }
 8388        }
 8389
 8390        // Ascend to the smallest ancestor that contains the range and has a task.
 8391        loop {
 8392            let node = cursor.node();
 8393            let node_range = node.byte_range();
 8394            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8395
 8396            // Check if this node contains our offset
 8397            if node_range.start <= offset && node_range.end >= offset {
 8398                // If it contains offset, check for task
 8399                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8400                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8401                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8402                }
 8403            }
 8404
 8405            if !cursor.goto_parent() {
 8406                break;
 8407            }
 8408        }
 8409        None
 8410    }
 8411
 8412    fn render_run_indicator(
 8413        &self,
 8414        _style: &EditorStyle,
 8415        is_active: bool,
 8416        row: DisplayRow,
 8417        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8418        cx: &mut Context<Self>,
 8419    ) -> IconButton {
 8420        let color = Color::Muted;
 8421        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8422
 8423        IconButton::new(
 8424            ("run_indicator", row.0 as usize),
 8425            ui::IconName::PlayOutlined,
 8426        )
 8427        .shape(ui::IconButtonShape::Square)
 8428        .icon_size(IconSize::XSmall)
 8429        .icon_color(color)
 8430        .toggle_state(is_active)
 8431        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8432            let quick_launch = match e {
 8433                ClickEvent::Keyboard(_) => true,
 8434                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8435            };
 8436
 8437            window.focus(&editor.focus_handle(cx));
 8438            editor.toggle_code_actions(
 8439                &ToggleCodeActions {
 8440                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8441                    quick_launch,
 8442                },
 8443                window,
 8444                cx,
 8445            );
 8446        }))
 8447        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8448            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8449        }))
 8450    }
 8451
 8452    pub fn context_menu_visible(&self) -> bool {
 8453        !self.edit_prediction_preview_is_active()
 8454            && self
 8455                .context_menu
 8456                .borrow()
 8457                .as_ref()
 8458                .is_some_and(|menu| menu.visible())
 8459    }
 8460
 8461    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8462        self.context_menu
 8463            .borrow()
 8464            .as_ref()
 8465            .map(|menu| menu.origin())
 8466    }
 8467
 8468    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8469        self.context_menu_options = Some(options);
 8470    }
 8471
 8472    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8473    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8474
 8475    fn render_edit_prediction_popover(
 8476        &mut self,
 8477        text_bounds: &Bounds<Pixels>,
 8478        content_origin: gpui::Point<Pixels>,
 8479        right_margin: Pixels,
 8480        editor_snapshot: &EditorSnapshot,
 8481        visible_row_range: Range<DisplayRow>,
 8482        scroll_top: ScrollOffset,
 8483        scroll_bottom: ScrollOffset,
 8484        line_layouts: &[LineWithInvisibles],
 8485        line_height: Pixels,
 8486        scroll_position: gpui::Point<ScrollOffset>,
 8487        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8488        newest_selection_head: Option<DisplayPoint>,
 8489        editor_width: Pixels,
 8490        style: &EditorStyle,
 8491        window: &mut Window,
 8492        cx: &mut App,
 8493    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8494        if self.mode().is_minimap() {
 8495            return None;
 8496        }
 8497        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8498
 8499        if self.edit_prediction_visible_in_cursor_popover(true) {
 8500            return None;
 8501        }
 8502
 8503        match &active_edit_prediction.completion {
 8504            EditPrediction::MoveWithin { target, .. } => {
 8505                let target_display_point = target.to_display_point(editor_snapshot);
 8506
 8507                if self.edit_prediction_requires_modifier() {
 8508                    if !self.edit_prediction_preview_is_active() {
 8509                        return None;
 8510                    }
 8511
 8512                    self.render_edit_prediction_modifier_jump_popover(
 8513                        text_bounds,
 8514                        content_origin,
 8515                        visible_row_range,
 8516                        line_layouts,
 8517                        line_height,
 8518                        scroll_pixel_position,
 8519                        newest_selection_head,
 8520                        target_display_point,
 8521                        window,
 8522                        cx,
 8523                    )
 8524                } else {
 8525                    self.render_edit_prediction_eager_jump_popover(
 8526                        text_bounds,
 8527                        content_origin,
 8528                        editor_snapshot,
 8529                        visible_row_range,
 8530                        scroll_top,
 8531                        scroll_bottom,
 8532                        line_height,
 8533                        scroll_pixel_position,
 8534                        target_display_point,
 8535                        editor_width,
 8536                        window,
 8537                        cx,
 8538                    )
 8539                }
 8540            }
 8541            EditPrediction::Edit {
 8542                display_mode: EditDisplayMode::Inline,
 8543                ..
 8544            } => None,
 8545            EditPrediction::Edit {
 8546                display_mode: EditDisplayMode::TabAccept,
 8547                edits,
 8548                ..
 8549            } => {
 8550                let range = &edits.first()?.0;
 8551                let target_display_point = range.end.to_display_point(editor_snapshot);
 8552
 8553                self.render_edit_prediction_end_of_line_popover(
 8554                    "Accept",
 8555                    editor_snapshot,
 8556                    visible_row_range,
 8557                    target_display_point,
 8558                    line_height,
 8559                    scroll_pixel_position,
 8560                    content_origin,
 8561                    editor_width,
 8562                    window,
 8563                    cx,
 8564                )
 8565            }
 8566            EditPrediction::Edit {
 8567                edits,
 8568                edit_preview,
 8569                display_mode: EditDisplayMode::DiffPopover,
 8570                snapshot,
 8571            } => self.render_edit_prediction_diff_popover(
 8572                text_bounds,
 8573                content_origin,
 8574                right_margin,
 8575                editor_snapshot,
 8576                visible_row_range,
 8577                line_layouts,
 8578                line_height,
 8579                scroll_position,
 8580                scroll_pixel_position,
 8581                newest_selection_head,
 8582                editor_width,
 8583                style,
 8584                edits,
 8585                edit_preview,
 8586                snapshot,
 8587                window,
 8588                cx,
 8589            ),
 8590            EditPrediction::MoveOutside { snapshot, .. } => {
 8591                let file_name = snapshot
 8592                    .file()
 8593                    .map(|file| file.file_name(cx))
 8594                    .unwrap_or("untitled");
 8595                let mut element = self
 8596                    .render_edit_prediction_line_popover(
 8597                        format!("Jump to {file_name}"),
 8598                        Some(IconName::ZedPredict),
 8599                        window,
 8600                        cx,
 8601                    )
 8602                    .into_any();
 8603
 8604                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8605                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8606                let origin_y = text_bounds.size.height - size.height - px(30.);
 8607                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8608                element.prepaint_at(origin, window, cx);
 8609
 8610                Some((element, origin))
 8611            }
 8612        }
 8613    }
 8614
 8615    fn render_edit_prediction_modifier_jump_popover(
 8616        &mut self,
 8617        text_bounds: &Bounds<Pixels>,
 8618        content_origin: gpui::Point<Pixels>,
 8619        visible_row_range: Range<DisplayRow>,
 8620        line_layouts: &[LineWithInvisibles],
 8621        line_height: Pixels,
 8622        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8623        newest_selection_head: Option<DisplayPoint>,
 8624        target_display_point: DisplayPoint,
 8625        window: &mut Window,
 8626        cx: &mut App,
 8627    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8628        let scrolled_content_origin =
 8629            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8630
 8631        const SCROLL_PADDING_Y: Pixels = px(12.);
 8632
 8633        if target_display_point.row() < visible_row_range.start {
 8634            return self.render_edit_prediction_scroll_popover(
 8635                |_| SCROLL_PADDING_Y,
 8636                IconName::ArrowUp,
 8637                visible_row_range,
 8638                line_layouts,
 8639                newest_selection_head,
 8640                scrolled_content_origin,
 8641                window,
 8642                cx,
 8643            );
 8644        } else if target_display_point.row() >= visible_row_range.end {
 8645            return self.render_edit_prediction_scroll_popover(
 8646                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8647                IconName::ArrowDown,
 8648                visible_row_range,
 8649                line_layouts,
 8650                newest_selection_head,
 8651                scrolled_content_origin,
 8652                window,
 8653                cx,
 8654            );
 8655        }
 8656
 8657        const POLE_WIDTH: Pixels = px(2.);
 8658
 8659        let line_layout =
 8660            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8661        let target_column = target_display_point.column() as usize;
 8662
 8663        let target_x = line_layout.x_for_index(target_column);
 8664        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8665            - scroll_pixel_position.y;
 8666
 8667        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8668
 8669        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8670        border_color.l += 0.001;
 8671
 8672        let mut element = v_flex()
 8673            .items_end()
 8674            .when(flag_on_right, |el| el.items_start())
 8675            .child(if flag_on_right {
 8676                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8677                    .rounded_bl(px(0.))
 8678                    .rounded_tl(px(0.))
 8679                    .border_l_2()
 8680                    .border_color(border_color)
 8681            } else {
 8682                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8683                    .rounded_br(px(0.))
 8684                    .rounded_tr(px(0.))
 8685                    .border_r_2()
 8686                    .border_color(border_color)
 8687            })
 8688            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8689            .into_any();
 8690
 8691        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8692
 8693        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8694            - point(
 8695                if flag_on_right {
 8696                    POLE_WIDTH
 8697                } else {
 8698                    size.width - POLE_WIDTH
 8699                },
 8700                size.height - line_height,
 8701            );
 8702
 8703        origin.x = origin.x.max(content_origin.x);
 8704
 8705        element.prepaint_at(origin, window, cx);
 8706
 8707        Some((element, origin))
 8708    }
 8709
 8710    fn render_edit_prediction_scroll_popover(
 8711        &mut self,
 8712        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8713        scroll_icon: IconName,
 8714        visible_row_range: Range<DisplayRow>,
 8715        line_layouts: &[LineWithInvisibles],
 8716        newest_selection_head: Option<DisplayPoint>,
 8717        scrolled_content_origin: gpui::Point<Pixels>,
 8718        window: &mut Window,
 8719        cx: &mut App,
 8720    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8721        let mut element = self
 8722            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8723            .into_any();
 8724
 8725        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8726
 8727        let cursor = newest_selection_head?;
 8728        let cursor_row_layout =
 8729            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8730        let cursor_column = cursor.column() as usize;
 8731
 8732        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8733
 8734        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8735
 8736        element.prepaint_at(origin, window, cx);
 8737        Some((element, origin))
 8738    }
 8739
 8740    fn render_edit_prediction_eager_jump_popover(
 8741        &mut self,
 8742        text_bounds: &Bounds<Pixels>,
 8743        content_origin: gpui::Point<Pixels>,
 8744        editor_snapshot: &EditorSnapshot,
 8745        visible_row_range: Range<DisplayRow>,
 8746        scroll_top: ScrollOffset,
 8747        scroll_bottom: ScrollOffset,
 8748        line_height: Pixels,
 8749        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8750        target_display_point: DisplayPoint,
 8751        editor_width: Pixels,
 8752        window: &mut Window,
 8753        cx: &mut App,
 8754    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8755        if target_display_point.row().as_f64() < scroll_top {
 8756            let mut element = self
 8757                .render_edit_prediction_line_popover(
 8758                    "Jump to Edit",
 8759                    Some(IconName::ArrowUp),
 8760                    window,
 8761                    cx,
 8762                )
 8763                .into_any();
 8764
 8765            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8766            let offset = point(
 8767                (text_bounds.size.width - size.width) / 2.,
 8768                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8769            );
 8770
 8771            let origin = text_bounds.origin + offset;
 8772            element.prepaint_at(origin, window, cx);
 8773            Some((element, origin))
 8774        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8775            let mut element = self
 8776                .render_edit_prediction_line_popover(
 8777                    "Jump to Edit",
 8778                    Some(IconName::ArrowDown),
 8779                    window,
 8780                    cx,
 8781                )
 8782                .into_any();
 8783
 8784            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8785            let offset = point(
 8786                (text_bounds.size.width - size.width) / 2.,
 8787                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8788            );
 8789
 8790            let origin = text_bounds.origin + offset;
 8791            element.prepaint_at(origin, window, cx);
 8792            Some((element, origin))
 8793        } else {
 8794            self.render_edit_prediction_end_of_line_popover(
 8795                "Jump to Edit",
 8796                editor_snapshot,
 8797                visible_row_range,
 8798                target_display_point,
 8799                line_height,
 8800                scroll_pixel_position,
 8801                content_origin,
 8802                editor_width,
 8803                window,
 8804                cx,
 8805            )
 8806        }
 8807    }
 8808
 8809    fn render_edit_prediction_end_of_line_popover(
 8810        self: &mut Editor,
 8811        label: &'static str,
 8812        editor_snapshot: &EditorSnapshot,
 8813        visible_row_range: Range<DisplayRow>,
 8814        target_display_point: DisplayPoint,
 8815        line_height: Pixels,
 8816        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8817        content_origin: gpui::Point<Pixels>,
 8818        editor_width: Pixels,
 8819        window: &mut Window,
 8820        cx: &mut App,
 8821    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8822        let target_line_end = DisplayPoint::new(
 8823            target_display_point.row(),
 8824            editor_snapshot.line_len(target_display_point.row()),
 8825        );
 8826
 8827        let mut element = self
 8828            .render_edit_prediction_line_popover(label, None, window, cx)
 8829            .into_any();
 8830
 8831        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8832
 8833        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8834
 8835        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8836        let mut origin = start_point
 8837            + line_origin
 8838            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8839        origin.x = origin.x.max(content_origin.x);
 8840
 8841        let max_x = content_origin.x + editor_width - size.width;
 8842
 8843        if origin.x > max_x {
 8844            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8845
 8846            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8847                origin.y += offset;
 8848                IconName::ArrowUp
 8849            } else {
 8850                origin.y -= offset;
 8851                IconName::ArrowDown
 8852            };
 8853
 8854            element = self
 8855                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 8856                .into_any();
 8857
 8858            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8859
 8860            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8861        }
 8862
 8863        element.prepaint_at(origin, window, cx);
 8864        Some((element, origin))
 8865    }
 8866
 8867    fn render_edit_prediction_diff_popover(
 8868        self: &Editor,
 8869        text_bounds: &Bounds<Pixels>,
 8870        content_origin: gpui::Point<Pixels>,
 8871        right_margin: Pixels,
 8872        editor_snapshot: &EditorSnapshot,
 8873        visible_row_range: Range<DisplayRow>,
 8874        line_layouts: &[LineWithInvisibles],
 8875        line_height: Pixels,
 8876        scroll_position: gpui::Point<ScrollOffset>,
 8877        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8878        newest_selection_head: Option<DisplayPoint>,
 8879        editor_width: Pixels,
 8880        style: &EditorStyle,
 8881        edits: &Vec<(Range<Anchor>, String)>,
 8882        edit_preview: &Option<language::EditPreview>,
 8883        snapshot: &language::BufferSnapshot,
 8884        window: &mut Window,
 8885        cx: &mut App,
 8886    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8887        let edit_start = edits
 8888            .first()
 8889            .unwrap()
 8890            .0
 8891            .start
 8892            .to_display_point(editor_snapshot);
 8893        let edit_end = edits
 8894            .last()
 8895            .unwrap()
 8896            .0
 8897            .end
 8898            .to_display_point(editor_snapshot);
 8899
 8900        let is_visible = visible_row_range.contains(&edit_start.row())
 8901            || visible_row_range.contains(&edit_end.row());
 8902        if !is_visible {
 8903            return None;
 8904        }
 8905
 8906        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8907            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8908        } else {
 8909            // Fallback for providers without edit_preview
 8910            crate::edit_prediction_fallback_text(edits, cx)
 8911        };
 8912
 8913        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8914        let line_count = highlighted_edits.text.lines().count();
 8915
 8916        const BORDER_WIDTH: Pixels = px(1.);
 8917
 8918        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8919        let has_keybind = keybind.is_some();
 8920
 8921        let mut element = h_flex()
 8922            .items_start()
 8923            .child(
 8924                h_flex()
 8925                    .bg(cx.theme().colors().editor_background)
 8926                    .border(BORDER_WIDTH)
 8927                    .shadow_xs()
 8928                    .border_color(cx.theme().colors().border)
 8929                    .rounded_l_lg()
 8930                    .when(line_count > 1, |el| el.rounded_br_lg())
 8931                    .pr_1()
 8932                    .child(styled_text),
 8933            )
 8934            .child(
 8935                h_flex()
 8936                    .h(line_height + BORDER_WIDTH * 2.)
 8937                    .px_1p5()
 8938                    .gap_1()
 8939                    // Workaround: For some reason, there's a gap if we don't do this
 8940                    .ml(-BORDER_WIDTH)
 8941                    .shadow(vec![gpui::BoxShadow {
 8942                        color: gpui::black().opacity(0.05),
 8943                        offset: point(px(1.), px(1.)),
 8944                        blur_radius: px(2.),
 8945                        spread_radius: px(0.),
 8946                    }])
 8947                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8948                    .border(BORDER_WIDTH)
 8949                    .border_color(cx.theme().colors().border)
 8950                    .rounded_r_lg()
 8951                    .id("edit_prediction_diff_popover_keybind")
 8952                    .when(!has_keybind, |el| {
 8953                        let status_colors = cx.theme().status();
 8954
 8955                        el.bg(status_colors.error_background)
 8956                            .border_color(status_colors.error.opacity(0.6))
 8957                            .child(Icon::new(IconName::Info).color(Color::Error))
 8958                            .cursor_default()
 8959                            .hoverable_tooltip(move |_window, cx| {
 8960                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8961                            })
 8962                    })
 8963                    .children(keybind),
 8964            )
 8965            .into_any();
 8966
 8967        let longest_row =
 8968            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8969        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8970            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8971        } else {
 8972            layout_line(
 8973                longest_row,
 8974                editor_snapshot,
 8975                style,
 8976                editor_width,
 8977                |_| false,
 8978                window,
 8979                cx,
 8980            )
 8981            .width
 8982        };
 8983
 8984        let viewport_bounds =
 8985            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8986                right: -right_margin,
 8987                ..Default::default()
 8988            });
 8989
 8990        let x_after_longest = Pixels::from(
 8991            ScrollPixelOffset::from(
 8992                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 8993            ) - scroll_pixel_position.x,
 8994        );
 8995
 8996        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8997
 8998        // Fully visible if it can be displayed within the window (allow overlapping other
 8999        // panes). However, this is only allowed if the popover starts within text_bounds.
 9000        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9001            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9002
 9003        let mut origin = if can_position_to_the_right {
 9004            point(
 9005                x_after_longest,
 9006                text_bounds.origin.y
 9007                    + Pixels::from(
 9008                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9009                            - scroll_pixel_position.y,
 9010                    ),
 9011            )
 9012        } else {
 9013            let cursor_row = newest_selection_head.map(|head| head.row());
 9014            let above_edit = edit_start
 9015                .row()
 9016                .0
 9017                .checked_sub(line_count as u32)
 9018                .map(DisplayRow);
 9019            let below_edit = Some(edit_end.row() + 1);
 9020            let above_cursor =
 9021                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9022            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9023
 9024            // Place the edit popover adjacent to the edit if there is a location
 9025            // available that is onscreen and does not obscure the cursor. Otherwise,
 9026            // place it adjacent to the cursor.
 9027            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9028                .into_iter()
 9029                .flatten()
 9030                .find(|&start_row| {
 9031                    let end_row = start_row + line_count as u32;
 9032                    visible_row_range.contains(&start_row)
 9033                        && visible_row_range.contains(&end_row)
 9034                        && cursor_row
 9035                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9036                })?;
 9037
 9038            content_origin
 9039                + point(
 9040                    Pixels::from(-scroll_pixel_position.x),
 9041                    Pixels::from(
 9042                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9043                    ),
 9044                )
 9045        };
 9046
 9047        origin.x -= BORDER_WIDTH;
 9048
 9049        window.defer_draw(element, origin, 1);
 9050
 9051        // Do not return an element, since it will already be drawn due to defer_draw.
 9052        None
 9053    }
 9054
 9055    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9056        px(30.)
 9057    }
 9058
 9059    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9060        if self.read_only(cx) {
 9061            cx.theme().players().read_only()
 9062        } else {
 9063            self.style.as_ref().unwrap().local_player
 9064        }
 9065    }
 9066
 9067    fn render_edit_prediction_accept_keybind(
 9068        &self,
 9069        window: &mut Window,
 9070        cx: &mut App,
 9071    ) -> Option<AnyElement> {
 9072        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9073        let accept_keystroke = accept_binding.keystroke()?;
 9074
 9075        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9076
 9077        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9078            Color::Accent
 9079        } else {
 9080            Color::Muted
 9081        };
 9082
 9083        h_flex()
 9084            .px_0p5()
 9085            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9086            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9087            .text_size(TextSize::XSmall.rems(cx))
 9088            .child(h_flex().children(ui::render_modifiers(
 9089                accept_keystroke.modifiers(),
 9090                PlatformStyle::platform(),
 9091                Some(modifiers_color),
 9092                Some(IconSize::XSmall.rems().into()),
 9093                true,
 9094            )))
 9095            .when(is_platform_style_mac, |parent| {
 9096                parent.child(accept_keystroke.key().to_string())
 9097            })
 9098            .when(!is_platform_style_mac, |parent| {
 9099                parent.child(
 9100                    Key::new(
 9101                        util::capitalize(accept_keystroke.key()),
 9102                        Some(Color::Default),
 9103                    )
 9104                    .size(Some(IconSize::XSmall.rems().into())),
 9105                )
 9106            })
 9107            .into_any()
 9108            .into()
 9109    }
 9110
 9111    fn render_edit_prediction_line_popover(
 9112        &self,
 9113        label: impl Into<SharedString>,
 9114        icon: Option<IconName>,
 9115        window: &mut Window,
 9116        cx: &mut App,
 9117    ) -> Stateful<Div> {
 9118        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9119
 9120        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9121        let has_keybind = keybind.is_some();
 9122
 9123        h_flex()
 9124            .id("ep-line-popover")
 9125            .py_0p5()
 9126            .pl_1()
 9127            .pr(padding_right)
 9128            .gap_1()
 9129            .rounded_md()
 9130            .border_1()
 9131            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9132            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9133            .shadow_xs()
 9134            .when(!has_keybind, |el| {
 9135                let status_colors = cx.theme().status();
 9136
 9137                el.bg(status_colors.error_background)
 9138                    .border_color(status_colors.error.opacity(0.6))
 9139                    .pl_2()
 9140                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9141                    .cursor_default()
 9142                    .hoverable_tooltip(move |_window, cx| {
 9143                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9144                    })
 9145            })
 9146            .children(keybind)
 9147            .child(
 9148                Label::new(label)
 9149                    .size(LabelSize::Small)
 9150                    .when(!has_keybind, |el| {
 9151                        el.color(cx.theme().status().error.into()).strikethrough()
 9152                    }),
 9153            )
 9154            .when(!has_keybind, |el| {
 9155                el.child(
 9156                    h_flex().ml_1().child(
 9157                        Icon::new(IconName::Info)
 9158                            .size(IconSize::Small)
 9159                            .color(cx.theme().status().error.into()),
 9160                    ),
 9161                )
 9162            })
 9163            .when_some(icon, |element, icon| {
 9164                element.child(
 9165                    div()
 9166                        .mt(px(1.5))
 9167                        .child(Icon::new(icon).size(IconSize::Small)),
 9168                )
 9169            })
 9170    }
 9171
 9172    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9173        let accent_color = cx.theme().colors().text_accent;
 9174        let editor_bg_color = cx.theme().colors().editor_background;
 9175        editor_bg_color.blend(accent_color.opacity(0.1))
 9176    }
 9177
 9178    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9179        let accent_color = cx.theme().colors().text_accent;
 9180        let editor_bg_color = cx.theme().colors().editor_background;
 9181        editor_bg_color.blend(accent_color.opacity(0.6))
 9182    }
 9183    fn get_prediction_provider_icon_name(
 9184        provider: &Option<RegisteredEditPredictionProvider>,
 9185    ) -> IconName {
 9186        match provider {
 9187            Some(provider) => match provider.provider.name() {
 9188                "copilot" => IconName::Copilot,
 9189                "supermaven" => IconName::Supermaven,
 9190                _ => IconName::ZedPredict,
 9191            },
 9192            None => IconName::ZedPredict,
 9193        }
 9194    }
 9195
 9196    fn render_edit_prediction_cursor_popover(
 9197        &self,
 9198        min_width: Pixels,
 9199        max_width: Pixels,
 9200        cursor_point: Point,
 9201        style: &EditorStyle,
 9202        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9203        _window: &Window,
 9204        cx: &mut Context<Editor>,
 9205    ) -> Option<AnyElement> {
 9206        let provider = self.edit_prediction_provider.as_ref()?;
 9207        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9208
 9209        let is_refreshing = provider.provider.is_refreshing(cx);
 9210
 9211        fn pending_completion_container(icon: IconName) -> Div {
 9212            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9213        }
 9214
 9215        let completion = match &self.active_edit_prediction {
 9216            Some(prediction) => {
 9217                if !self.has_visible_completions_menu() {
 9218                    const RADIUS: Pixels = px(6.);
 9219                    const BORDER_WIDTH: Pixels = px(1.);
 9220
 9221                    return Some(
 9222                        h_flex()
 9223                            .elevation_2(cx)
 9224                            .border(BORDER_WIDTH)
 9225                            .border_color(cx.theme().colors().border)
 9226                            .when(accept_keystroke.is_none(), |el| {
 9227                                el.border_color(cx.theme().status().error)
 9228                            })
 9229                            .rounded(RADIUS)
 9230                            .rounded_tl(px(0.))
 9231                            .overflow_hidden()
 9232                            .child(div().px_1p5().child(match &prediction.completion {
 9233                                EditPrediction::MoveWithin { target, snapshot } => {
 9234                                    use text::ToPoint as _;
 9235                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9236                                    {
 9237                                        Icon::new(IconName::ZedPredictDown)
 9238                                    } else {
 9239                                        Icon::new(IconName::ZedPredictUp)
 9240                                    }
 9241                                }
 9242                                EditPrediction::MoveOutside { .. } => {
 9243                                    // TODO [zeta2] custom icon for external jump?
 9244                                    Icon::new(provider_icon)
 9245                                }
 9246                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9247                            }))
 9248                            .child(
 9249                                h_flex()
 9250                                    .gap_1()
 9251                                    .py_1()
 9252                                    .px_2()
 9253                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9254                                    .border_l_1()
 9255                                    .border_color(cx.theme().colors().border)
 9256                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9257                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9258                                        el.child(
 9259                                            Label::new("Hold")
 9260                                                .size(LabelSize::Small)
 9261                                                .when(accept_keystroke.is_none(), |el| {
 9262                                                    el.strikethrough()
 9263                                                })
 9264                                                .line_height_style(LineHeightStyle::UiLabel),
 9265                                        )
 9266                                    })
 9267                                    .id("edit_prediction_cursor_popover_keybind")
 9268                                    .when(accept_keystroke.is_none(), |el| {
 9269                                        let status_colors = cx.theme().status();
 9270
 9271                                        el.bg(status_colors.error_background)
 9272                                            .border_color(status_colors.error.opacity(0.6))
 9273                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9274                                            .cursor_default()
 9275                                            .hoverable_tooltip(move |_window, cx| {
 9276                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9277                                                    .into()
 9278                                            })
 9279                                    })
 9280                                    .when_some(
 9281                                        accept_keystroke.as_ref(),
 9282                                        |el, accept_keystroke| {
 9283                                            el.child(h_flex().children(ui::render_modifiers(
 9284                                                accept_keystroke.modifiers(),
 9285                                                PlatformStyle::platform(),
 9286                                                Some(Color::Default),
 9287                                                Some(IconSize::XSmall.rems().into()),
 9288                                                false,
 9289                                            )))
 9290                                        },
 9291                                    ),
 9292                            )
 9293                            .into_any(),
 9294                    );
 9295                }
 9296
 9297                self.render_edit_prediction_cursor_popover_preview(
 9298                    prediction,
 9299                    cursor_point,
 9300                    style,
 9301                    cx,
 9302                )?
 9303            }
 9304
 9305            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9306                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9307                    stale_completion,
 9308                    cursor_point,
 9309                    style,
 9310                    cx,
 9311                )?,
 9312
 9313                None => pending_completion_container(provider_icon)
 9314                    .child(Label::new("...").size(LabelSize::Small)),
 9315            },
 9316
 9317            None => pending_completion_container(provider_icon)
 9318                .child(Label::new("...").size(LabelSize::Small)),
 9319        };
 9320
 9321        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9322            completion
 9323                .with_animation(
 9324                    "loading-completion",
 9325                    Animation::new(Duration::from_secs(2))
 9326                        .repeat()
 9327                        .with_easing(pulsating_between(0.4, 0.8)),
 9328                    |label, delta| label.opacity(delta),
 9329                )
 9330                .into_any_element()
 9331        } else {
 9332            completion.into_any_element()
 9333        };
 9334
 9335        let has_completion = self.active_edit_prediction.is_some();
 9336
 9337        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9338        Some(
 9339            h_flex()
 9340                .min_w(min_width)
 9341                .max_w(max_width)
 9342                .flex_1()
 9343                .elevation_2(cx)
 9344                .border_color(cx.theme().colors().border)
 9345                .child(
 9346                    div()
 9347                        .flex_1()
 9348                        .py_1()
 9349                        .px_2()
 9350                        .overflow_hidden()
 9351                        .child(completion),
 9352                )
 9353                .when_some(accept_keystroke, |el, accept_keystroke| {
 9354                    if !accept_keystroke.modifiers().modified() {
 9355                        return el;
 9356                    }
 9357
 9358                    el.child(
 9359                        h_flex()
 9360                            .h_full()
 9361                            .border_l_1()
 9362                            .rounded_r_lg()
 9363                            .border_color(cx.theme().colors().border)
 9364                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9365                            .gap_1()
 9366                            .py_1()
 9367                            .px_2()
 9368                            .child(
 9369                                h_flex()
 9370                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9371                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9372                                    .child(h_flex().children(ui::render_modifiers(
 9373                                        accept_keystroke.modifiers(),
 9374                                        PlatformStyle::platform(),
 9375                                        Some(if !has_completion {
 9376                                            Color::Muted
 9377                                        } else {
 9378                                            Color::Default
 9379                                        }),
 9380                                        None,
 9381                                        false,
 9382                                    ))),
 9383                            )
 9384                            .child(Label::new("Preview").into_any_element())
 9385                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9386                    )
 9387                })
 9388                .into_any(),
 9389        )
 9390    }
 9391
 9392    fn render_edit_prediction_cursor_popover_preview(
 9393        &self,
 9394        completion: &EditPredictionState,
 9395        cursor_point: Point,
 9396        style: &EditorStyle,
 9397        cx: &mut Context<Editor>,
 9398    ) -> Option<Div> {
 9399        use text::ToPoint as _;
 9400
 9401        fn render_relative_row_jump(
 9402            prefix: impl Into<String>,
 9403            current_row: u32,
 9404            target_row: u32,
 9405        ) -> Div {
 9406            let (row_diff, arrow) = if target_row < current_row {
 9407                (current_row - target_row, IconName::ArrowUp)
 9408            } else {
 9409                (target_row - current_row, IconName::ArrowDown)
 9410            };
 9411
 9412            h_flex()
 9413                .child(
 9414                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9415                        .color(Color::Muted)
 9416                        .size(LabelSize::Small),
 9417                )
 9418                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9419        }
 9420
 9421        let supports_jump = self
 9422            .edit_prediction_provider
 9423            .as_ref()
 9424            .map(|provider| provider.provider.supports_jump_to_edit())
 9425            .unwrap_or(true);
 9426
 9427        match &completion.completion {
 9428            EditPrediction::MoveWithin {
 9429                target, snapshot, ..
 9430            } => {
 9431                if !supports_jump {
 9432                    return None;
 9433                }
 9434
 9435                Some(
 9436                    h_flex()
 9437                        .px_2()
 9438                        .gap_2()
 9439                        .flex_1()
 9440                        .child(
 9441                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9442                                Icon::new(IconName::ZedPredictDown)
 9443                            } else {
 9444                                Icon::new(IconName::ZedPredictUp)
 9445                            },
 9446                        )
 9447                        .child(Label::new("Jump to Edit")),
 9448                )
 9449            }
 9450            EditPrediction::MoveOutside { snapshot, .. } => {
 9451                let file_name = snapshot
 9452                    .file()
 9453                    .map(|file| file.file_name(cx))
 9454                    .unwrap_or("untitled");
 9455                Some(
 9456                    h_flex()
 9457                        .px_2()
 9458                        .gap_2()
 9459                        .flex_1()
 9460                        .child(Icon::new(IconName::ZedPredict))
 9461                        .child(Label::new(format!("Jump to {file_name}"))),
 9462                )
 9463            }
 9464            EditPrediction::Edit {
 9465                edits,
 9466                edit_preview,
 9467                snapshot,
 9468                display_mode: _,
 9469            } => {
 9470                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9471
 9472                let (highlighted_edits, has_more_lines) =
 9473                    if let Some(edit_preview) = edit_preview.as_ref() {
 9474                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9475                            .first_line_preview()
 9476                    } else {
 9477                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9478                    };
 9479
 9480                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9481                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9482
 9483                let preview = h_flex()
 9484                    .gap_1()
 9485                    .min_w_16()
 9486                    .child(styled_text)
 9487                    .when(has_more_lines, |parent| parent.child(""));
 9488
 9489                let left = if supports_jump && first_edit_row != cursor_point.row {
 9490                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9491                        .into_any_element()
 9492                } else {
 9493                    let icon_name =
 9494                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9495                    Icon::new(icon_name).into_any_element()
 9496                };
 9497
 9498                Some(
 9499                    h_flex()
 9500                        .h_full()
 9501                        .flex_1()
 9502                        .gap_2()
 9503                        .pr_1()
 9504                        .overflow_x_hidden()
 9505                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9506                        .child(left)
 9507                        .child(preview),
 9508                )
 9509            }
 9510        }
 9511    }
 9512
 9513    pub fn render_context_menu(
 9514        &self,
 9515        style: &EditorStyle,
 9516        max_height_in_lines: u32,
 9517        window: &mut Window,
 9518        cx: &mut Context<Editor>,
 9519    ) -> Option<AnyElement> {
 9520        let menu = self.context_menu.borrow();
 9521        let menu = menu.as_ref()?;
 9522        if !menu.visible() {
 9523            return None;
 9524        };
 9525        Some(menu.render(style, max_height_in_lines, window, cx))
 9526    }
 9527
 9528    fn render_context_menu_aside(
 9529        &mut self,
 9530        max_size: Size<Pixels>,
 9531        window: &mut Window,
 9532        cx: &mut Context<Editor>,
 9533    ) -> Option<AnyElement> {
 9534        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9535            if menu.visible() {
 9536                menu.render_aside(max_size, window, cx)
 9537            } else {
 9538                None
 9539            }
 9540        })
 9541    }
 9542
 9543    fn hide_context_menu(
 9544        &mut self,
 9545        window: &mut Window,
 9546        cx: &mut Context<Self>,
 9547    ) -> Option<CodeContextMenu> {
 9548        cx.notify();
 9549        self.completion_tasks.clear();
 9550        let context_menu = self.context_menu.borrow_mut().take();
 9551        self.stale_edit_prediction_in_menu.take();
 9552        self.update_visible_edit_prediction(window, cx);
 9553        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9554            && let Some(completion_provider) = &self.completion_provider
 9555        {
 9556            completion_provider.selection_changed(None, window, cx);
 9557        }
 9558        context_menu
 9559    }
 9560
 9561    fn show_snippet_choices(
 9562        &mut self,
 9563        choices: &Vec<String>,
 9564        selection: Range<Anchor>,
 9565        cx: &mut Context<Self>,
 9566    ) {
 9567        let Some((_, buffer, _)) = self
 9568            .buffer()
 9569            .read(cx)
 9570            .excerpt_containing(selection.start, cx)
 9571        else {
 9572            return;
 9573        };
 9574        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9575        else {
 9576            return;
 9577        };
 9578        if buffer != end_buffer {
 9579            log::error!("expected anchor range to have matching buffer IDs");
 9580            return;
 9581        }
 9582
 9583        let id = post_inc(&mut self.next_completion_id);
 9584        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9585        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9586            CompletionsMenu::new_snippet_choices(
 9587                id,
 9588                true,
 9589                choices,
 9590                selection,
 9591                buffer,
 9592                snippet_sort_order,
 9593            ),
 9594        ));
 9595    }
 9596
 9597    pub fn insert_snippet(
 9598        &mut self,
 9599        insertion_ranges: &[Range<usize>],
 9600        snippet: Snippet,
 9601        window: &mut Window,
 9602        cx: &mut Context<Self>,
 9603    ) -> Result<()> {
 9604        struct Tabstop<T> {
 9605            is_end_tabstop: bool,
 9606            ranges: Vec<Range<T>>,
 9607            choices: Option<Vec<String>>,
 9608        }
 9609
 9610        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9611            let snippet_text: Arc<str> = snippet.text.clone().into();
 9612            let edits = insertion_ranges
 9613                .iter()
 9614                .cloned()
 9615                .map(|range| (range, snippet_text.clone()));
 9616            let autoindent_mode = AutoindentMode::Block {
 9617                original_indent_columns: Vec::new(),
 9618            };
 9619            buffer.edit(edits, Some(autoindent_mode), cx);
 9620
 9621            let snapshot = &*buffer.read(cx);
 9622            let snippet = &snippet;
 9623            snippet
 9624                .tabstops
 9625                .iter()
 9626                .map(|tabstop| {
 9627                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9628                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9629                    });
 9630                    let mut tabstop_ranges = tabstop
 9631                        .ranges
 9632                        .iter()
 9633                        .flat_map(|tabstop_range| {
 9634                            let mut delta = 0_isize;
 9635                            insertion_ranges.iter().map(move |insertion_range| {
 9636                                let insertion_start = insertion_range.start as isize + delta;
 9637                                delta +=
 9638                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9639
 9640                                let start = ((insertion_start + tabstop_range.start) as usize)
 9641                                    .min(snapshot.len());
 9642                                let end = ((insertion_start + tabstop_range.end) as usize)
 9643                                    .min(snapshot.len());
 9644                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9645                            })
 9646                        })
 9647                        .collect::<Vec<_>>();
 9648                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9649
 9650                    Tabstop {
 9651                        is_end_tabstop,
 9652                        ranges: tabstop_ranges,
 9653                        choices: tabstop.choices.clone(),
 9654                    }
 9655                })
 9656                .collect::<Vec<_>>()
 9657        });
 9658        if let Some(tabstop) = tabstops.first() {
 9659            self.change_selections(Default::default(), window, cx, |s| {
 9660                // Reverse order so that the first range is the newest created selection.
 9661                // Completions will use it and autoscroll will prioritize it.
 9662                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9663            });
 9664
 9665            if let Some(choices) = &tabstop.choices
 9666                && let Some(selection) = tabstop.ranges.first()
 9667            {
 9668                self.show_snippet_choices(choices, selection.clone(), cx)
 9669            }
 9670
 9671            // If we're already at the last tabstop and it's at the end of the snippet,
 9672            // we're done, we don't need to keep the state around.
 9673            if !tabstop.is_end_tabstop {
 9674                let choices = tabstops
 9675                    .iter()
 9676                    .map(|tabstop| tabstop.choices.clone())
 9677                    .collect();
 9678
 9679                let ranges = tabstops
 9680                    .into_iter()
 9681                    .map(|tabstop| tabstop.ranges)
 9682                    .collect::<Vec<_>>();
 9683
 9684                self.snippet_stack.push(SnippetState {
 9685                    active_index: 0,
 9686                    ranges,
 9687                    choices,
 9688                });
 9689            }
 9690
 9691            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9692            if self.autoclose_regions.is_empty() {
 9693                let snapshot = self.buffer.read(cx).snapshot(cx);
 9694                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9695                    let selection_head = selection.head();
 9696                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9697                        continue;
 9698                    };
 9699
 9700                    let mut bracket_pair = None;
 9701                    let max_lookup_length = scope
 9702                        .brackets()
 9703                        .map(|(pair, _)| {
 9704                            pair.start
 9705                                .as_str()
 9706                                .chars()
 9707                                .count()
 9708                                .max(pair.end.as_str().chars().count())
 9709                        })
 9710                        .max();
 9711                    if let Some(max_lookup_length) = max_lookup_length {
 9712                        let next_text = snapshot
 9713                            .chars_at(selection_head)
 9714                            .take(max_lookup_length)
 9715                            .collect::<String>();
 9716                        let prev_text = snapshot
 9717                            .reversed_chars_at(selection_head)
 9718                            .take(max_lookup_length)
 9719                            .collect::<String>();
 9720
 9721                        for (pair, enabled) in scope.brackets() {
 9722                            if enabled
 9723                                && pair.close
 9724                                && prev_text.starts_with(pair.start.as_str())
 9725                                && next_text.starts_with(pair.end.as_str())
 9726                            {
 9727                                bracket_pair = Some(pair.clone());
 9728                                break;
 9729                            }
 9730                        }
 9731                    }
 9732
 9733                    if let Some(pair) = bracket_pair {
 9734                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9735                        let autoclose_enabled =
 9736                            self.use_autoclose && snapshot_settings.use_autoclose;
 9737                        if autoclose_enabled {
 9738                            let start = snapshot.anchor_after(selection_head);
 9739                            let end = snapshot.anchor_after(selection_head);
 9740                            self.autoclose_regions.push(AutocloseRegion {
 9741                                selection_id: selection.id,
 9742                                range: start..end,
 9743                                pair,
 9744                            });
 9745                        }
 9746                    }
 9747                }
 9748            }
 9749        }
 9750        Ok(())
 9751    }
 9752
 9753    pub fn move_to_next_snippet_tabstop(
 9754        &mut self,
 9755        window: &mut Window,
 9756        cx: &mut Context<Self>,
 9757    ) -> bool {
 9758        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9759    }
 9760
 9761    pub fn move_to_prev_snippet_tabstop(
 9762        &mut self,
 9763        window: &mut Window,
 9764        cx: &mut Context<Self>,
 9765    ) -> bool {
 9766        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9767    }
 9768
 9769    pub fn move_to_snippet_tabstop(
 9770        &mut self,
 9771        bias: Bias,
 9772        window: &mut Window,
 9773        cx: &mut Context<Self>,
 9774    ) -> bool {
 9775        if let Some(mut snippet) = self.snippet_stack.pop() {
 9776            match bias {
 9777                Bias::Left => {
 9778                    if snippet.active_index > 0 {
 9779                        snippet.active_index -= 1;
 9780                    } else {
 9781                        self.snippet_stack.push(snippet);
 9782                        return false;
 9783                    }
 9784                }
 9785                Bias::Right => {
 9786                    if snippet.active_index + 1 < snippet.ranges.len() {
 9787                        snippet.active_index += 1;
 9788                    } else {
 9789                        self.snippet_stack.push(snippet);
 9790                        return false;
 9791                    }
 9792                }
 9793            }
 9794            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9795                self.change_selections(Default::default(), window, cx, |s| {
 9796                    // Reverse order so that the first range is the newest created selection.
 9797                    // Completions will use it and autoscroll will prioritize it.
 9798                    s.select_ranges(current_ranges.iter().rev().cloned())
 9799                });
 9800
 9801                if let Some(choices) = &snippet.choices[snippet.active_index]
 9802                    && let Some(selection) = current_ranges.first()
 9803                {
 9804                    self.show_snippet_choices(choices, selection.clone(), cx);
 9805                }
 9806
 9807                // If snippet state is not at the last tabstop, push it back on the stack
 9808                if snippet.active_index + 1 < snippet.ranges.len() {
 9809                    self.snippet_stack.push(snippet);
 9810                }
 9811                return true;
 9812            }
 9813        }
 9814
 9815        false
 9816    }
 9817
 9818    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9819        self.transact(window, cx, |this, window, cx| {
 9820            this.select_all(&SelectAll, window, cx);
 9821            this.insert("", window, cx);
 9822        });
 9823    }
 9824
 9825    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9826        if self.read_only(cx) {
 9827            return;
 9828        }
 9829        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9830        self.transact(window, cx, |this, window, cx| {
 9831            this.select_autoclose_pair(window, cx);
 9832
 9833            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9834
 9835            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9836            if !this.linked_edit_ranges.is_empty() {
 9837                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9838                let snapshot = this.buffer.read(cx).snapshot(cx);
 9839
 9840                for selection in selections.iter() {
 9841                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9842                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9843                    if selection_start.buffer_id != selection_end.buffer_id {
 9844                        continue;
 9845                    }
 9846                    if let Some(ranges) =
 9847                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9848                    {
 9849                        for (buffer, entries) in ranges {
 9850                            linked_ranges.entry(buffer).or_default().extend(entries);
 9851                        }
 9852                    }
 9853                }
 9854            }
 9855
 9856            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9857            for selection in &mut selections {
 9858                if selection.is_empty() {
 9859                    let old_head = selection.head();
 9860                    let mut new_head =
 9861                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9862                            .to_point(&display_map);
 9863                    if let Some((buffer, line_buffer_range)) = display_map
 9864                        .buffer_snapshot()
 9865                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9866                    {
 9867                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9868                        let indent_len = match indent_size.kind {
 9869                            IndentKind::Space => {
 9870                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9871                            }
 9872                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9873                        };
 9874                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9875                            let indent_len = indent_len.get();
 9876                            new_head = cmp::min(
 9877                                new_head,
 9878                                MultiBufferPoint::new(
 9879                                    old_head.row,
 9880                                    ((old_head.column - 1) / indent_len) * indent_len,
 9881                                ),
 9882                            );
 9883                        }
 9884                    }
 9885
 9886                    selection.set_head(new_head, SelectionGoal::None);
 9887                }
 9888            }
 9889
 9890            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9891            this.insert("", window, cx);
 9892            let empty_str: Arc<str> = Arc::from("");
 9893            for (buffer, edits) in linked_ranges {
 9894                let snapshot = buffer.read(cx).snapshot();
 9895                use text::ToPoint as TP;
 9896
 9897                let edits = edits
 9898                    .into_iter()
 9899                    .map(|range| {
 9900                        let end_point = TP::to_point(&range.end, &snapshot);
 9901                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9902
 9903                        if end_point == start_point {
 9904                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9905                                .saturating_sub(1);
 9906                            start_point =
 9907                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9908                        };
 9909
 9910                        (start_point..end_point, empty_str.clone())
 9911                    })
 9912                    .sorted_by_key(|(range, _)| range.start)
 9913                    .collect::<Vec<_>>();
 9914                buffer.update(cx, |this, cx| {
 9915                    this.edit(edits, None, cx);
 9916                })
 9917            }
 9918            this.refresh_edit_prediction(true, false, window, cx);
 9919            refresh_linked_ranges(this, window, cx);
 9920        });
 9921    }
 9922
 9923    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9924        if self.read_only(cx) {
 9925            return;
 9926        }
 9927        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9928        self.transact(window, cx, |this, window, cx| {
 9929            this.change_selections(Default::default(), window, cx, |s| {
 9930                s.move_with(|map, selection| {
 9931                    if selection.is_empty() {
 9932                        let cursor = movement::right(map, selection.head());
 9933                        selection.end = cursor;
 9934                        selection.reversed = true;
 9935                        selection.goal = SelectionGoal::None;
 9936                    }
 9937                })
 9938            });
 9939            this.insert("", window, cx);
 9940            this.refresh_edit_prediction(true, false, window, cx);
 9941        });
 9942    }
 9943
 9944    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9945        if self.mode.is_single_line() {
 9946            cx.propagate();
 9947            return;
 9948        }
 9949
 9950        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9951        if self.move_to_prev_snippet_tabstop(window, cx) {
 9952            return;
 9953        }
 9954        self.outdent(&Outdent, window, cx);
 9955    }
 9956
 9957    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9958        if self.mode.is_single_line() {
 9959            cx.propagate();
 9960            return;
 9961        }
 9962
 9963        if self.move_to_next_snippet_tabstop(window, cx) {
 9964            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9965            return;
 9966        }
 9967        if self.read_only(cx) {
 9968            return;
 9969        }
 9970        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9971        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 9972        let buffer = self.buffer.read(cx);
 9973        let snapshot = buffer.snapshot(cx);
 9974        let rows_iter = selections.iter().map(|s| s.head().row);
 9975        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9976
 9977        let has_some_cursor_in_whitespace = selections
 9978            .iter()
 9979            .filter(|selection| selection.is_empty())
 9980            .any(|selection| {
 9981                let cursor = selection.head();
 9982                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9983                cursor.column < current_indent.len
 9984            });
 9985
 9986        let mut edits = Vec::new();
 9987        let mut prev_edited_row = 0;
 9988        let mut row_delta = 0;
 9989        for selection in &mut selections {
 9990            if selection.start.row != prev_edited_row {
 9991                row_delta = 0;
 9992            }
 9993            prev_edited_row = selection.end.row;
 9994
 9995            // If the selection is non-empty, then increase the indentation of the selected lines.
 9996            if !selection.is_empty() {
 9997                row_delta =
 9998                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9999                continue;
10000            }
10001
10002            let cursor = selection.head();
10003            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10004            if let Some(suggested_indent) =
10005                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10006            {
10007                // Don't do anything if already at suggested indent
10008                // and there is any other cursor which is not
10009                if has_some_cursor_in_whitespace
10010                    && cursor.column == current_indent.len
10011                    && current_indent.len == suggested_indent.len
10012                {
10013                    continue;
10014                }
10015
10016                // Adjust line and move cursor to suggested indent
10017                // if cursor is not at suggested indent
10018                if cursor.column < suggested_indent.len
10019                    && cursor.column <= current_indent.len
10020                    && current_indent.len <= suggested_indent.len
10021                {
10022                    selection.start = Point::new(cursor.row, suggested_indent.len);
10023                    selection.end = selection.start;
10024                    if row_delta == 0 {
10025                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10026                            cursor.row,
10027                            current_indent,
10028                            suggested_indent,
10029                        ));
10030                        row_delta = suggested_indent.len - current_indent.len;
10031                    }
10032                    continue;
10033                }
10034
10035                // If current indent is more than suggested indent
10036                // only move cursor to current indent and skip indent
10037                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10038                    selection.start = Point::new(cursor.row, current_indent.len);
10039                    selection.end = selection.start;
10040                    continue;
10041                }
10042            }
10043
10044            // Otherwise, insert a hard or soft tab.
10045            let settings = buffer.language_settings_at(cursor, cx);
10046            let tab_size = if settings.hard_tabs {
10047                IndentSize::tab()
10048            } else {
10049                let tab_size = settings.tab_size.get();
10050                let indent_remainder = snapshot
10051                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10052                    .flat_map(str::chars)
10053                    .fold(row_delta % tab_size, |counter: u32, c| {
10054                        if c == '\t' {
10055                            0
10056                        } else {
10057                            (counter + 1) % tab_size
10058                        }
10059                    });
10060
10061                let chars_to_next_tab_stop = tab_size - indent_remainder;
10062                IndentSize::spaces(chars_to_next_tab_stop)
10063            };
10064            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10065            selection.end = selection.start;
10066            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10067            row_delta += tab_size.len;
10068        }
10069
10070        self.transact(window, cx, |this, window, cx| {
10071            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10072            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10073            this.refresh_edit_prediction(true, false, window, cx);
10074        });
10075    }
10076
10077    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10078        if self.read_only(cx) {
10079            return;
10080        }
10081        if self.mode.is_single_line() {
10082            cx.propagate();
10083            return;
10084        }
10085
10086        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10087        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10088        let mut prev_edited_row = 0;
10089        let mut row_delta = 0;
10090        let mut edits = Vec::new();
10091        let buffer = self.buffer.read(cx);
10092        let snapshot = buffer.snapshot(cx);
10093        for selection in &mut selections {
10094            if selection.start.row != prev_edited_row {
10095                row_delta = 0;
10096            }
10097            prev_edited_row = selection.end.row;
10098
10099            row_delta =
10100                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10101        }
10102
10103        self.transact(window, cx, |this, window, cx| {
10104            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10105            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10106        });
10107    }
10108
10109    fn indent_selection(
10110        buffer: &MultiBuffer,
10111        snapshot: &MultiBufferSnapshot,
10112        selection: &mut Selection<Point>,
10113        edits: &mut Vec<(Range<Point>, String)>,
10114        delta_for_start_row: u32,
10115        cx: &App,
10116    ) -> u32 {
10117        let settings = buffer.language_settings_at(selection.start, cx);
10118        let tab_size = settings.tab_size.get();
10119        let indent_kind = if settings.hard_tabs {
10120            IndentKind::Tab
10121        } else {
10122            IndentKind::Space
10123        };
10124        let mut start_row = selection.start.row;
10125        let mut end_row = selection.end.row + 1;
10126
10127        // If a selection ends at the beginning of a line, don't indent
10128        // that last line.
10129        if selection.end.column == 0 && selection.end.row > selection.start.row {
10130            end_row -= 1;
10131        }
10132
10133        // Avoid re-indenting a row that has already been indented by a
10134        // previous selection, but still update this selection's column
10135        // to reflect that indentation.
10136        if delta_for_start_row > 0 {
10137            start_row += 1;
10138            selection.start.column += delta_for_start_row;
10139            if selection.end.row == selection.start.row {
10140                selection.end.column += delta_for_start_row;
10141            }
10142        }
10143
10144        let mut delta_for_end_row = 0;
10145        let has_multiple_rows = start_row + 1 != end_row;
10146        for row in start_row..end_row {
10147            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10148            let indent_delta = match (current_indent.kind, indent_kind) {
10149                (IndentKind::Space, IndentKind::Space) => {
10150                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10151                    IndentSize::spaces(columns_to_next_tab_stop)
10152                }
10153                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10154                (_, IndentKind::Tab) => IndentSize::tab(),
10155            };
10156
10157            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10158                0
10159            } else {
10160                selection.start.column
10161            };
10162            let row_start = Point::new(row, start);
10163            edits.push((
10164                row_start..row_start,
10165                indent_delta.chars().collect::<String>(),
10166            ));
10167
10168            // Update this selection's endpoints to reflect the indentation.
10169            if row == selection.start.row {
10170                selection.start.column += indent_delta.len;
10171            }
10172            if row == selection.end.row {
10173                selection.end.column += indent_delta.len;
10174                delta_for_end_row = indent_delta.len;
10175            }
10176        }
10177
10178        if selection.start.row == selection.end.row {
10179            delta_for_start_row + delta_for_end_row
10180        } else {
10181            delta_for_end_row
10182        }
10183    }
10184
10185    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10186        if self.read_only(cx) {
10187            return;
10188        }
10189        if self.mode.is_single_line() {
10190            cx.propagate();
10191            return;
10192        }
10193
10194        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10195        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10196        let selections = self.selections.all::<Point>(&display_map);
10197        let mut deletion_ranges = Vec::new();
10198        let mut last_outdent = None;
10199        {
10200            let buffer = self.buffer.read(cx);
10201            let snapshot = buffer.snapshot(cx);
10202            for selection in &selections {
10203                let settings = buffer.language_settings_at(selection.start, cx);
10204                let tab_size = settings.tab_size.get();
10205                let mut rows = selection.spanned_rows(false, &display_map);
10206
10207                // Avoid re-outdenting a row that has already been outdented by a
10208                // previous selection.
10209                if let Some(last_row) = last_outdent
10210                    && last_row == rows.start
10211                {
10212                    rows.start = rows.start.next_row();
10213                }
10214                let has_multiple_rows = rows.len() > 1;
10215                for row in rows.iter_rows() {
10216                    let indent_size = snapshot.indent_size_for_line(row);
10217                    if indent_size.len > 0 {
10218                        let deletion_len = match indent_size.kind {
10219                            IndentKind::Space => {
10220                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10221                                if columns_to_prev_tab_stop == 0 {
10222                                    tab_size
10223                                } else {
10224                                    columns_to_prev_tab_stop
10225                                }
10226                            }
10227                            IndentKind::Tab => 1,
10228                        };
10229                        let start = if has_multiple_rows
10230                            || deletion_len > selection.start.column
10231                            || indent_size.len < selection.start.column
10232                        {
10233                            0
10234                        } else {
10235                            selection.start.column - deletion_len
10236                        };
10237                        deletion_ranges.push(
10238                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10239                        );
10240                        last_outdent = Some(row);
10241                    }
10242                }
10243            }
10244        }
10245
10246        self.transact(window, cx, |this, window, cx| {
10247            this.buffer.update(cx, |buffer, cx| {
10248                let empty_str: Arc<str> = Arc::default();
10249                buffer.edit(
10250                    deletion_ranges
10251                        .into_iter()
10252                        .map(|range| (range, empty_str.clone())),
10253                    None,
10254                    cx,
10255                );
10256            });
10257            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10258            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10259        });
10260    }
10261
10262    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10263        if self.read_only(cx) {
10264            return;
10265        }
10266        if self.mode.is_single_line() {
10267            cx.propagate();
10268            return;
10269        }
10270
10271        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10272        let selections = self
10273            .selections
10274            .all::<usize>(&self.display_snapshot(cx))
10275            .into_iter()
10276            .map(|s| s.range());
10277
10278        self.transact(window, cx, |this, window, cx| {
10279            this.buffer.update(cx, |buffer, cx| {
10280                buffer.autoindent_ranges(selections, cx);
10281            });
10282            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10283            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10284        });
10285    }
10286
10287    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10288        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10289        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10290        let selections = self.selections.all::<Point>(&display_map);
10291
10292        let mut new_cursors = Vec::new();
10293        let mut edit_ranges = Vec::new();
10294        let mut selections = selections.iter().peekable();
10295        while let Some(selection) = selections.next() {
10296            let mut rows = selection.spanned_rows(false, &display_map);
10297
10298            // Accumulate contiguous regions of rows that we want to delete.
10299            while let Some(next_selection) = selections.peek() {
10300                let next_rows = next_selection.spanned_rows(false, &display_map);
10301                if next_rows.start <= rows.end {
10302                    rows.end = next_rows.end;
10303                    selections.next().unwrap();
10304                } else {
10305                    break;
10306                }
10307            }
10308
10309            let buffer = display_map.buffer_snapshot();
10310            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10311            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10312                // If there's a line after the range, delete the \n from the end of the row range
10313                (
10314                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10315                    rows.end,
10316                )
10317            } else {
10318                // If there isn't a line after the range, delete the \n from the line before the
10319                // start of the row range
10320                edit_start = edit_start.saturating_sub(1);
10321                (buffer.len(), rows.start.previous_row())
10322            };
10323
10324            let text_layout_details = self.text_layout_details(window);
10325            let x = display_map.x_for_display_point(
10326                selection.head().to_display_point(&display_map),
10327                &text_layout_details,
10328            );
10329            let row = Point::new(target_row.0, 0)
10330                .to_display_point(&display_map)
10331                .row();
10332            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10333
10334            new_cursors.push((
10335                selection.id,
10336                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10337                SelectionGoal::None,
10338            ));
10339            edit_ranges.push(edit_start..edit_end);
10340        }
10341
10342        self.transact(window, cx, |this, window, cx| {
10343            let buffer = this.buffer.update(cx, |buffer, cx| {
10344                let empty_str: Arc<str> = Arc::default();
10345                buffer.edit(
10346                    edit_ranges
10347                        .into_iter()
10348                        .map(|range| (range, empty_str.clone())),
10349                    None,
10350                    cx,
10351                );
10352                buffer.snapshot(cx)
10353            });
10354            let new_selections = new_cursors
10355                .into_iter()
10356                .map(|(id, cursor, goal)| {
10357                    let cursor = cursor.to_point(&buffer);
10358                    Selection {
10359                        id,
10360                        start: cursor,
10361                        end: cursor,
10362                        reversed: false,
10363                        goal,
10364                    }
10365                })
10366                .collect();
10367
10368            this.change_selections(Default::default(), window, cx, |s| {
10369                s.select(new_selections);
10370            });
10371        });
10372    }
10373
10374    pub fn join_lines_impl(
10375        &mut self,
10376        insert_whitespace: bool,
10377        window: &mut Window,
10378        cx: &mut Context<Self>,
10379    ) {
10380        if self.read_only(cx) {
10381            return;
10382        }
10383        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10384        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10385            let start = MultiBufferRow(selection.start.row);
10386            // Treat single line selections as if they include the next line. Otherwise this action
10387            // would do nothing for single line selections individual cursors.
10388            let end = if selection.start.row == selection.end.row {
10389                MultiBufferRow(selection.start.row + 1)
10390            } else {
10391                MultiBufferRow(selection.end.row)
10392            };
10393
10394            if let Some(last_row_range) = row_ranges.last_mut()
10395                && start <= last_row_range.end
10396            {
10397                last_row_range.end = end;
10398                continue;
10399            }
10400            row_ranges.push(start..end);
10401        }
10402
10403        let snapshot = self.buffer.read(cx).snapshot(cx);
10404        let mut cursor_positions = Vec::new();
10405        for row_range in &row_ranges {
10406            let anchor = snapshot.anchor_before(Point::new(
10407                row_range.end.previous_row().0,
10408                snapshot.line_len(row_range.end.previous_row()),
10409            ));
10410            cursor_positions.push(anchor..anchor);
10411        }
10412
10413        self.transact(window, cx, |this, window, cx| {
10414            for row_range in row_ranges.into_iter().rev() {
10415                for row in row_range.iter_rows().rev() {
10416                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10417                    let next_line_row = row.next_row();
10418                    let indent = snapshot.indent_size_for_line(next_line_row);
10419                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10420
10421                    let replace =
10422                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10423                            " "
10424                        } else {
10425                            ""
10426                        };
10427
10428                    this.buffer.update(cx, |buffer, cx| {
10429                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10430                    });
10431                }
10432            }
10433
10434            this.change_selections(Default::default(), window, cx, |s| {
10435                s.select_anchor_ranges(cursor_positions)
10436            });
10437        });
10438    }
10439
10440    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10441        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10442        self.join_lines_impl(true, window, cx);
10443    }
10444
10445    pub fn sort_lines_case_sensitive(
10446        &mut self,
10447        _: &SortLinesCaseSensitive,
10448        window: &mut Window,
10449        cx: &mut Context<Self>,
10450    ) {
10451        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10452    }
10453
10454    pub fn sort_lines_by_length(
10455        &mut self,
10456        _: &SortLinesByLength,
10457        window: &mut Window,
10458        cx: &mut Context<Self>,
10459    ) {
10460        self.manipulate_immutable_lines(window, cx, |lines| {
10461            lines.sort_by_key(|&line| line.chars().count())
10462        })
10463    }
10464
10465    pub fn sort_lines_case_insensitive(
10466        &mut self,
10467        _: &SortLinesCaseInsensitive,
10468        window: &mut Window,
10469        cx: &mut Context<Self>,
10470    ) {
10471        self.manipulate_immutable_lines(window, cx, |lines| {
10472            lines.sort_by_key(|line| line.to_lowercase())
10473        })
10474    }
10475
10476    pub fn unique_lines_case_insensitive(
10477        &mut self,
10478        _: &UniqueLinesCaseInsensitive,
10479        window: &mut Window,
10480        cx: &mut Context<Self>,
10481    ) {
10482        self.manipulate_immutable_lines(window, cx, |lines| {
10483            let mut seen = HashSet::default();
10484            lines.retain(|line| seen.insert(line.to_lowercase()));
10485        })
10486    }
10487
10488    pub fn unique_lines_case_sensitive(
10489        &mut self,
10490        _: &UniqueLinesCaseSensitive,
10491        window: &mut Window,
10492        cx: &mut Context<Self>,
10493    ) {
10494        self.manipulate_immutable_lines(window, cx, |lines| {
10495            let mut seen = HashSet::default();
10496            lines.retain(|line| seen.insert(*line));
10497        })
10498    }
10499
10500    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10501        let snapshot = self.buffer.read(cx).snapshot(cx);
10502        for selection in self.selections.disjoint_anchors_arc().iter() {
10503            if snapshot
10504                .language_at(selection.start)
10505                .and_then(|lang| lang.config().wrap_characters.as_ref())
10506                .is_some()
10507            {
10508                return true;
10509            }
10510        }
10511        false
10512    }
10513
10514    fn wrap_selections_in_tag(
10515        &mut self,
10516        _: &WrapSelectionsInTag,
10517        window: &mut Window,
10518        cx: &mut Context<Self>,
10519    ) {
10520        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10521
10522        let snapshot = self.buffer.read(cx).snapshot(cx);
10523
10524        let mut edits = Vec::new();
10525        let mut boundaries = Vec::new();
10526
10527        for selection in self
10528            .selections
10529            .all::<Point>(&self.display_snapshot(cx))
10530            .iter()
10531        {
10532            let Some(wrap_config) = snapshot
10533                .language_at(selection.start)
10534                .and_then(|lang| lang.config().wrap_characters.clone())
10535            else {
10536                continue;
10537            };
10538
10539            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10540            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10541
10542            let start_before = snapshot.anchor_before(selection.start);
10543            let end_after = snapshot.anchor_after(selection.end);
10544
10545            edits.push((start_before..start_before, open_tag));
10546            edits.push((end_after..end_after, close_tag));
10547
10548            boundaries.push((
10549                start_before,
10550                end_after,
10551                wrap_config.start_prefix.len(),
10552                wrap_config.end_suffix.len(),
10553            ));
10554        }
10555
10556        if edits.is_empty() {
10557            return;
10558        }
10559
10560        self.transact(window, cx, |this, window, cx| {
10561            let buffer = this.buffer.update(cx, |buffer, cx| {
10562                buffer.edit(edits, None, cx);
10563                buffer.snapshot(cx)
10564            });
10565
10566            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10567            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10568                boundaries.into_iter()
10569            {
10570                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10571                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10572                new_selections.push(open_offset..open_offset);
10573                new_selections.push(close_offset..close_offset);
10574            }
10575
10576            this.change_selections(Default::default(), window, cx, |s| {
10577                s.select_ranges(new_selections);
10578            });
10579
10580            this.request_autoscroll(Autoscroll::fit(), cx);
10581        });
10582    }
10583
10584    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10585        let Some(project) = self.project.clone() else {
10586            return;
10587        };
10588        self.reload(project, window, cx)
10589            .detach_and_notify_err(window, cx);
10590    }
10591
10592    pub fn restore_file(
10593        &mut self,
10594        _: &::git::RestoreFile,
10595        window: &mut Window,
10596        cx: &mut Context<Self>,
10597    ) {
10598        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10599        let mut buffer_ids = HashSet::default();
10600        let snapshot = self.buffer().read(cx).snapshot(cx);
10601        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10602            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10603        }
10604
10605        let buffer = self.buffer().read(cx);
10606        let ranges = buffer_ids
10607            .into_iter()
10608            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10609            .collect::<Vec<_>>();
10610
10611        self.restore_hunks_in_ranges(ranges, window, cx);
10612    }
10613
10614    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10615        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10616        let selections = self
10617            .selections
10618            .all(&self.display_snapshot(cx))
10619            .into_iter()
10620            .map(|s| s.range())
10621            .collect();
10622        self.restore_hunks_in_ranges(selections, window, cx);
10623    }
10624
10625    pub fn restore_hunks_in_ranges(
10626        &mut self,
10627        ranges: Vec<Range<Point>>,
10628        window: &mut Window,
10629        cx: &mut Context<Editor>,
10630    ) {
10631        let mut revert_changes = HashMap::default();
10632        let chunk_by = self
10633            .snapshot(window, cx)
10634            .hunks_for_ranges(ranges)
10635            .into_iter()
10636            .chunk_by(|hunk| hunk.buffer_id);
10637        for (buffer_id, hunks) in &chunk_by {
10638            let hunks = hunks.collect::<Vec<_>>();
10639            for hunk in &hunks {
10640                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10641            }
10642            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10643        }
10644        drop(chunk_by);
10645        if !revert_changes.is_empty() {
10646            self.transact(window, cx, |editor, window, cx| {
10647                editor.restore(revert_changes, window, cx);
10648            });
10649        }
10650    }
10651
10652    pub fn open_active_item_in_terminal(
10653        &mut self,
10654        _: &OpenInTerminal,
10655        window: &mut Window,
10656        cx: &mut Context<Self>,
10657    ) {
10658        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10659            let project_path = buffer.read(cx).project_path(cx)?;
10660            let project = self.project()?.read(cx);
10661            let entry = project.entry_for_path(&project_path, cx)?;
10662            let parent = match &entry.canonical_path {
10663                Some(canonical_path) => canonical_path.to_path_buf(),
10664                None => project.absolute_path(&project_path, cx)?,
10665            }
10666            .parent()?
10667            .to_path_buf();
10668            Some(parent)
10669        }) {
10670            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10671        }
10672    }
10673
10674    fn set_breakpoint_context_menu(
10675        &mut self,
10676        display_row: DisplayRow,
10677        position: Option<Anchor>,
10678        clicked_point: gpui::Point<Pixels>,
10679        window: &mut Window,
10680        cx: &mut Context<Self>,
10681    ) {
10682        let source = self
10683            .buffer
10684            .read(cx)
10685            .snapshot(cx)
10686            .anchor_before(Point::new(display_row.0, 0u32));
10687
10688        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10689
10690        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10691            self,
10692            source,
10693            clicked_point,
10694            context_menu,
10695            window,
10696            cx,
10697        );
10698    }
10699
10700    fn add_edit_breakpoint_block(
10701        &mut self,
10702        anchor: Anchor,
10703        breakpoint: &Breakpoint,
10704        edit_action: BreakpointPromptEditAction,
10705        window: &mut Window,
10706        cx: &mut Context<Self>,
10707    ) {
10708        let weak_editor = cx.weak_entity();
10709        let bp_prompt = cx.new(|cx| {
10710            BreakpointPromptEditor::new(
10711                weak_editor,
10712                anchor,
10713                breakpoint.clone(),
10714                edit_action,
10715                window,
10716                cx,
10717            )
10718        });
10719
10720        let height = bp_prompt.update(cx, |this, cx| {
10721            this.prompt
10722                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10723        });
10724        let cloned_prompt = bp_prompt.clone();
10725        let blocks = vec![BlockProperties {
10726            style: BlockStyle::Sticky,
10727            placement: BlockPlacement::Above(anchor),
10728            height: Some(height),
10729            render: Arc::new(move |cx| {
10730                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10731                cloned_prompt.clone().into_any_element()
10732            }),
10733            priority: 0,
10734        }];
10735
10736        let focus_handle = bp_prompt.focus_handle(cx);
10737        window.focus(&focus_handle);
10738
10739        let block_ids = self.insert_blocks(blocks, None, cx);
10740        bp_prompt.update(cx, |prompt, _| {
10741            prompt.add_block_ids(block_ids);
10742        });
10743    }
10744
10745    pub(crate) fn breakpoint_at_row(
10746        &self,
10747        row: u32,
10748        window: &mut Window,
10749        cx: &mut Context<Self>,
10750    ) -> Option<(Anchor, Breakpoint)> {
10751        let snapshot = self.snapshot(window, cx);
10752        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10753
10754        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10755    }
10756
10757    pub(crate) fn breakpoint_at_anchor(
10758        &self,
10759        breakpoint_position: Anchor,
10760        snapshot: &EditorSnapshot,
10761        cx: &mut Context<Self>,
10762    ) -> Option<(Anchor, Breakpoint)> {
10763        let buffer = self
10764            .buffer
10765            .read(cx)
10766            .buffer_for_anchor(breakpoint_position, cx)?;
10767
10768        let enclosing_excerpt = breakpoint_position.excerpt_id;
10769        let buffer_snapshot = buffer.read(cx).snapshot();
10770
10771        let row = buffer_snapshot
10772            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10773            .row;
10774
10775        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10776        let anchor_end = snapshot
10777            .buffer_snapshot()
10778            .anchor_after(Point::new(row, line_len));
10779
10780        self.breakpoint_store
10781            .as_ref()?
10782            .read_with(cx, |breakpoint_store, cx| {
10783                breakpoint_store
10784                    .breakpoints(
10785                        &buffer,
10786                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10787                        &buffer_snapshot,
10788                        cx,
10789                    )
10790                    .next()
10791                    .and_then(|(bp, _)| {
10792                        let breakpoint_row = buffer_snapshot
10793                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10794                            .row;
10795
10796                        if breakpoint_row == row {
10797                            snapshot
10798                                .buffer_snapshot()
10799                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10800                                .map(|position| (position, bp.bp.clone()))
10801                        } else {
10802                            None
10803                        }
10804                    })
10805            })
10806    }
10807
10808    pub fn edit_log_breakpoint(
10809        &mut self,
10810        _: &EditLogBreakpoint,
10811        window: &mut Window,
10812        cx: &mut Context<Self>,
10813    ) {
10814        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10815            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10816                message: None,
10817                state: BreakpointState::Enabled,
10818                condition: None,
10819                hit_condition: None,
10820            });
10821
10822            self.add_edit_breakpoint_block(
10823                anchor,
10824                &breakpoint,
10825                BreakpointPromptEditAction::Log,
10826                window,
10827                cx,
10828            );
10829        }
10830    }
10831
10832    fn breakpoints_at_cursors(
10833        &self,
10834        window: &mut Window,
10835        cx: &mut Context<Self>,
10836    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10837        let snapshot = self.snapshot(window, cx);
10838        let cursors = self
10839            .selections
10840            .disjoint_anchors_arc()
10841            .iter()
10842            .map(|selection| {
10843                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
10844
10845                let breakpoint_position = self
10846                    .breakpoint_at_row(cursor_position.row, window, cx)
10847                    .map(|bp| bp.0)
10848                    .unwrap_or_else(|| {
10849                        snapshot
10850                            .display_snapshot
10851                            .buffer_snapshot()
10852                            .anchor_after(Point::new(cursor_position.row, 0))
10853                    });
10854
10855                let breakpoint = self
10856                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10857                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10858
10859                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10860            })
10861            // 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.
10862            .collect::<HashMap<Anchor, _>>();
10863
10864        cursors.into_iter().collect()
10865    }
10866
10867    pub fn enable_breakpoint(
10868        &mut self,
10869        _: &crate::actions::EnableBreakpoint,
10870        window: &mut Window,
10871        cx: &mut Context<Self>,
10872    ) {
10873        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10874            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10875                continue;
10876            };
10877            self.edit_breakpoint_at_anchor(
10878                anchor,
10879                breakpoint,
10880                BreakpointEditAction::InvertState,
10881                cx,
10882            );
10883        }
10884    }
10885
10886    pub fn disable_breakpoint(
10887        &mut self,
10888        _: &crate::actions::DisableBreakpoint,
10889        window: &mut Window,
10890        cx: &mut Context<Self>,
10891    ) {
10892        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10893            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10894                continue;
10895            };
10896            self.edit_breakpoint_at_anchor(
10897                anchor,
10898                breakpoint,
10899                BreakpointEditAction::InvertState,
10900                cx,
10901            );
10902        }
10903    }
10904
10905    pub fn toggle_breakpoint(
10906        &mut self,
10907        _: &crate::actions::ToggleBreakpoint,
10908        window: &mut Window,
10909        cx: &mut Context<Self>,
10910    ) {
10911        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10912            if let Some(breakpoint) = breakpoint {
10913                self.edit_breakpoint_at_anchor(
10914                    anchor,
10915                    breakpoint,
10916                    BreakpointEditAction::Toggle,
10917                    cx,
10918                );
10919            } else {
10920                self.edit_breakpoint_at_anchor(
10921                    anchor,
10922                    Breakpoint::new_standard(),
10923                    BreakpointEditAction::Toggle,
10924                    cx,
10925                );
10926            }
10927        }
10928    }
10929
10930    pub fn edit_breakpoint_at_anchor(
10931        &mut self,
10932        breakpoint_position: Anchor,
10933        breakpoint: Breakpoint,
10934        edit_action: BreakpointEditAction,
10935        cx: &mut Context<Self>,
10936    ) {
10937        let Some(breakpoint_store) = &self.breakpoint_store else {
10938            return;
10939        };
10940
10941        let Some(buffer) = self
10942            .buffer
10943            .read(cx)
10944            .buffer_for_anchor(breakpoint_position, cx)
10945        else {
10946            return;
10947        };
10948
10949        breakpoint_store.update(cx, |breakpoint_store, cx| {
10950            breakpoint_store.toggle_breakpoint(
10951                buffer,
10952                BreakpointWithPosition {
10953                    position: breakpoint_position.text_anchor,
10954                    bp: breakpoint,
10955                },
10956                edit_action,
10957                cx,
10958            );
10959        });
10960
10961        cx.notify();
10962    }
10963
10964    #[cfg(any(test, feature = "test-support"))]
10965    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10966        self.breakpoint_store.clone()
10967    }
10968
10969    pub fn prepare_restore_change(
10970        &self,
10971        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10972        hunk: &MultiBufferDiffHunk,
10973        cx: &mut App,
10974    ) -> Option<()> {
10975        if hunk.is_created_file() {
10976            return None;
10977        }
10978        let buffer = self.buffer.read(cx);
10979        let diff = buffer.diff_for(hunk.buffer_id)?;
10980        let buffer = buffer.buffer(hunk.buffer_id)?;
10981        let buffer = buffer.read(cx);
10982        let original_text = diff
10983            .read(cx)
10984            .base_text()
10985            .as_rope()
10986            .slice(hunk.diff_base_byte_range.clone());
10987        let buffer_snapshot = buffer.snapshot();
10988        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10989        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10990            probe
10991                .0
10992                .start
10993                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10994                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10995        }) {
10996            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10997            Some(())
10998        } else {
10999            None
11000        }
11001    }
11002
11003    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11004        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11005    }
11006
11007    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11008        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11009    }
11010
11011    fn manipulate_lines<M>(
11012        &mut self,
11013        window: &mut Window,
11014        cx: &mut Context<Self>,
11015        mut manipulate: M,
11016    ) where
11017        M: FnMut(&str) -> LineManipulationResult,
11018    {
11019        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11020
11021        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11022        let buffer = self.buffer.read(cx).snapshot(cx);
11023
11024        let mut edits = Vec::new();
11025
11026        let selections = self.selections.all::<Point>(&display_map);
11027        let mut selections = selections.iter().peekable();
11028        let mut contiguous_row_selections = Vec::new();
11029        let mut new_selections = Vec::new();
11030        let mut added_lines = 0;
11031        let mut removed_lines = 0;
11032
11033        while let Some(selection) = selections.next() {
11034            let (start_row, end_row) = consume_contiguous_rows(
11035                &mut contiguous_row_selections,
11036                selection,
11037                &display_map,
11038                &mut selections,
11039            );
11040
11041            let start_point = Point::new(start_row.0, 0);
11042            let end_point = Point::new(
11043                end_row.previous_row().0,
11044                buffer.line_len(end_row.previous_row()),
11045            );
11046            let text = buffer
11047                .text_for_range(start_point..end_point)
11048                .collect::<String>();
11049
11050            let LineManipulationResult {
11051                new_text,
11052                line_count_before,
11053                line_count_after,
11054            } = manipulate(&text);
11055
11056            edits.push((start_point..end_point, new_text));
11057
11058            // Selections must change based on added and removed line count
11059            let start_row =
11060                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11061            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11062            new_selections.push(Selection {
11063                id: selection.id,
11064                start: start_row,
11065                end: end_row,
11066                goal: SelectionGoal::None,
11067                reversed: selection.reversed,
11068            });
11069
11070            if line_count_after > line_count_before {
11071                added_lines += line_count_after - line_count_before;
11072            } else if line_count_before > line_count_after {
11073                removed_lines += line_count_before - line_count_after;
11074            }
11075        }
11076
11077        self.transact(window, cx, |this, window, cx| {
11078            let buffer = this.buffer.update(cx, |buffer, cx| {
11079                buffer.edit(edits, None, cx);
11080                buffer.snapshot(cx)
11081            });
11082
11083            // Recalculate offsets on newly edited buffer
11084            let new_selections = new_selections
11085                .iter()
11086                .map(|s| {
11087                    let start_point = Point::new(s.start.0, 0);
11088                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11089                    Selection {
11090                        id: s.id,
11091                        start: buffer.point_to_offset(start_point),
11092                        end: buffer.point_to_offset(end_point),
11093                        goal: s.goal,
11094                        reversed: s.reversed,
11095                    }
11096                })
11097                .collect();
11098
11099            this.change_selections(Default::default(), window, cx, |s| {
11100                s.select(new_selections);
11101            });
11102
11103            this.request_autoscroll(Autoscroll::fit(), cx);
11104        });
11105    }
11106
11107    fn manipulate_immutable_lines<Fn>(
11108        &mut self,
11109        window: &mut Window,
11110        cx: &mut Context<Self>,
11111        mut callback: Fn,
11112    ) where
11113        Fn: FnMut(&mut Vec<&str>),
11114    {
11115        self.manipulate_lines(window, cx, |text| {
11116            let mut lines: Vec<&str> = text.split('\n').collect();
11117            let line_count_before = lines.len();
11118
11119            callback(&mut lines);
11120
11121            LineManipulationResult {
11122                new_text: lines.join("\n"),
11123                line_count_before,
11124                line_count_after: lines.len(),
11125            }
11126        });
11127    }
11128
11129    fn manipulate_mutable_lines<Fn>(
11130        &mut self,
11131        window: &mut Window,
11132        cx: &mut Context<Self>,
11133        mut callback: Fn,
11134    ) where
11135        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11136    {
11137        self.manipulate_lines(window, cx, |text| {
11138            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11139            let line_count_before = lines.len();
11140
11141            callback(&mut lines);
11142
11143            LineManipulationResult {
11144                new_text: lines.join("\n"),
11145                line_count_before,
11146                line_count_after: lines.len(),
11147            }
11148        });
11149    }
11150
11151    pub fn convert_indentation_to_spaces(
11152        &mut self,
11153        _: &ConvertIndentationToSpaces,
11154        window: &mut Window,
11155        cx: &mut Context<Self>,
11156    ) {
11157        let settings = self.buffer.read(cx).language_settings(cx);
11158        let tab_size = settings.tab_size.get() as usize;
11159
11160        self.manipulate_mutable_lines(window, cx, |lines| {
11161            // Allocates a reasonably sized scratch buffer once for the whole loop
11162            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11163            // Avoids recomputing spaces that could be inserted many times
11164            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11165                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11166                .collect();
11167
11168            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11169                let mut chars = line.as_ref().chars();
11170                let mut col = 0;
11171                let mut changed = false;
11172
11173                for ch in chars.by_ref() {
11174                    match ch {
11175                        ' ' => {
11176                            reindented_line.push(' ');
11177                            col += 1;
11178                        }
11179                        '\t' => {
11180                            // \t are converted to spaces depending on the current column
11181                            let spaces_len = tab_size - (col % tab_size);
11182                            reindented_line.extend(&space_cache[spaces_len - 1]);
11183                            col += spaces_len;
11184                            changed = true;
11185                        }
11186                        _ => {
11187                            // If we dont append before break, the character is consumed
11188                            reindented_line.push(ch);
11189                            break;
11190                        }
11191                    }
11192                }
11193
11194                if !changed {
11195                    reindented_line.clear();
11196                    continue;
11197                }
11198                // Append the rest of the line and replace old reference with new one
11199                reindented_line.extend(chars);
11200                *line = Cow::Owned(reindented_line.clone());
11201                reindented_line.clear();
11202            }
11203        });
11204    }
11205
11206    pub fn convert_indentation_to_tabs(
11207        &mut self,
11208        _: &ConvertIndentationToTabs,
11209        window: &mut Window,
11210        cx: &mut Context<Self>,
11211    ) {
11212        let settings = self.buffer.read(cx).language_settings(cx);
11213        let tab_size = settings.tab_size.get() as usize;
11214
11215        self.manipulate_mutable_lines(window, cx, |lines| {
11216            // Allocates a reasonably sized buffer once for the whole loop
11217            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11218            // Avoids recomputing spaces that could be inserted many times
11219            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11220                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11221                .collect();
11222
11223            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11224                let mut chars = line.chars();
11225                let mut spaces_count = 0;
11226                let mut first_non_indent_char = None;
11227                let mut changed = false;
11228
11229                for ch in chars.by_ref() {
11230                    match ch {
11231                        ' ' => {
11232                            // Keep track of spaces. Append \t when we reach tab_size
11233                            spaces_count += 1;
11234                            changed = true;
11235                            if spaces_count == tab_size {
11236                                reindented_line.push('\t');
11237                                spaces_count = 0;
11238                            }
11239                        }
11240                        '\t' => {
11241                            reindented_line.push('\t');
11242                            spaces_count = 0;
11243                        }
11244                        _ => {
11245                            // Dont append it yet, we might have remaining spaces
11246                            first_non_indent_char = Some(ch);
11247                            break;
11248                        }
11249                    }
11250                }
11251
11252                if !changed {
11253                    reindented_line.clear();
11254                    continue;
11255                }
11256                // Remaining spaces that didn't make a full tab stop
11257                if spaces_count > 0 {
11258                    reindented_line.extend(&space_cache[spaces_count - 1]);
11259                }
11260                // If we consume an extra character that was not indentation, add it back
11261                if let Some(extra_char) = first_non_indent_char {
11262                    reindented_line.push(extra_char);
11263                }
11264                // Append the rest of the line and replace old reference with new one
11265                reindented_line.extend(chars);
11266                *line = Cow::Owned(reindented_line.clone());
11267                reindented_line.clear();
11268            }
11269        });
11270    }
11271
11272    pub fn convert_to_upper_case(
11273        &mut self,
11274        _: &ConvertToUpperCase,
11275        window: &mut Window,
11276        cx: &mut Context<Self>,
11277    ) {
11278        self.manipulate_text(window, cx, |text| text.to_uppercase())
11279    }
11280
11281    pub fn convert_to_lower_case(
11282        &mut self,
11283        _: &ConvertToLowerCase,
11284        window: &mut Window,
11285        cx: &mut Context<Self>,
11286    ) {
11287        self.manipulate_text(window, cx, |text| text.to_lowercase())
11288    }
11289
11290    pub fn convert_to_title_case(
11291        &mut self,
11292        _: &ConvertToTitleCase,
11293        window: &mut Window,
11294        cx: &mut Context<Self>,
11295    ) {
11296        self.manipulate_text(window, cx, |text| {
11297            text.split('\n')
11298                .map(|line| line.to_case(Case::Title))
11299                .join("\n")
11300        })
11301    }
11302
11303    pub fn convert_to_snake_case(
11304        &mut self,
11305        _: &ConvertToSnakeCase,
11306        window: &mut Window,
11307        cx: &mut Context<Self>,
11308    ) {
11309        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11310    }
11311
11312    pub fn convert_to_kebab_case(
11313        &mut self,
11314        _: &ConvertToKebabCase,
11315        window: &mut Window,
11316        cx: &mut Context<Self>,
11317    ) {
11318        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11319    }
11320
11321    pub fn convert_to_upper_camel_case(
11322        &mut self,
11323        _: &ConvertToUpperCamelCase,
11324        window: &mut Window,
11325        cx: &mut Context<Self>,
11326    ) {
11327        self.manipulate_text(window, cx, |text| {
11328            text.split('\n')
11329                .map(|line| line.to_case(Case::UpperCamel))
11330                .join("\n")
11331        })
11332    }
11333
11334    pub fn convert_to_lower_camel_case(
11335        &mut self,
11336        _: &ConvertToLowerCamelCase,
11337        window: &mut Window,
11338        cx: &mut Context<Self>,
11339    ) {
11340        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11341    }
11342
11343    pub fn convert_to_opposite_case(
11344        &mut self,
11345        _: &ConvertToOppositeCase,
11346        window: &mut Window,
11347        cx: &mut Context<Self>,
11348    ) {
11349        self.manipulate_text(window, cx, |text| {
11350            text.chars()
11351                .fold(String::with_capacity(text.len()), |mut t, c| {
11352                    if c.is_uppercase() {
11353                        t.extend(c.to_lowercase());
11354                    } else {
11355                        t.extend(c.to_uppercase());
11356                    }
11357                    t
11358                })
11359        })
11360    }
11361
11362    pub fn convert_to_sentence_case(
11363        &mut self,
11364        _: &ConvertToSentenceCase,
11365        window: &mut Window,
11366        cx: &mut Context<Self>,
11367    ) {
11368        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11369    }
11370
11371    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11372        self.manipulate_text(window, cx, |text| {
11373            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11374            if has_upper_case_characters {
11375                text.to_lowercase()
11376            } else {
11377                text.to_uppercase()
11378            }
11379        })
11380    }
11381
11382    pub fn convert_to_rot13(
11383        &mut self,
11384        _: &ConvertToRot13,
11385        window: &mut Window,
11386        cx: &mut Context<Self>,
11387    ) {
11388        self.manipulate_text(window, cx, |text| {
11389            text.chars()
11390                .map(|c| match c {
11391                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11392                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11393                    _ => c,
11394                })
11395                .collect()
11396        })
11397    }
11398
11399    pub fn convert_to_rot47(
11400        &mut self,
11401        _: &ConvertToRot47,
11402        window: &mut Window,
11403        cx: &mut Context<Self>,
11404    ) {
11405        self.manipulate_text(window, cx, |text| {
11406            text.chars()
11407                .map(|c| {
11408                    let code_point = c as u32;
11409                    if code_point >= 33 && code_point <= 126 {
11410                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11411                    }
11412                    c
11413                })
11414                .collect()
11415        })
11416    }
11417
11418    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11419    where
11420        Fn: FnMut(&str) -> String,
11421    {
11422        let buffer = self.buffer.read(cx).snapshot(cx);
11423
11424        let mut new_selections = Vec::new();
11425        let mut edits = Vec::new();
11426        let mut selection_adjustment = 0i32;
11427
11428        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11429            let selection_is_empty = selection.is_empty();
11430
11431            let (start, end) = if selection_is_empty {
11432                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11433                (word_range.start, word_range.end)
11434            } else {
11435                (
11436                    buffer.point_to_offset(selection.start),
11437                    buffer.point_to_offset(selection.end),
11438                )
11439            };
11440
11441            let text = buffer.text_for_range(start..end).collect::<String>();
11442            let old_length = text.len() as i32;
11443            let text = callback(&text);
11444
11445            new_selections.push(Selection {
11446                start: (start as i32 - selection_adjustment) as usize,
11447                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11448                goal: SelectionGoal::None,
11449                id: selection.id,
11450                reversed: selection.reversed,
11451            });
11452
11453            selection_adjustment += old_length - text.len() as i32;
11454
11455            edits.push((start..end, text));
11456        }
11457
11458        self.transact(window, cx, |this, window, cx| {
11459            this.buffer.update(cx, |buffer, cx| {
11460                buffer.edit(edits, None, cx);
11461            });
11462
11463            this.change_selections(Default::default(), window, cx, |s| {
11464                s.select(new_selections);
11465            });
11466
11467            this.request_autoscroll(Autoscroll::fit(), cx);
11468        });
11469    }
11470
11471    pub fn move_selection_on_drop(
11472        &mut self,
11473        selection: &Selection<Anchor>,
11474        target: DisplayPoint,
11475        is_cut: bool,
11476        window: &mut Window,
11477        cx: &mut Context<Self>,
11478    ) {
11479        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11480        let buffer = display_map.buffer_snapshot();
11481        let mut edits = Vec::new();
11482        let insert_point = display_map
11483            .clip_point(target, Bias::Left)
11484            .to_point(&display_map);
11485        let text = buffer
11486            .text_for_range(selection.start..selection.end)
11487            .collect::<String>();
11488        if is_cut {
11489            edits.push(((selection.start..selection.end), String::new()));
11490        }
11491        let insert_anchor = buffer.anchor_before(insert_point);
11492        edits.push(((insert_anchor..insert_anchor), text));
11493        let last_edit_start = insert_anchor.bias_left(buffer);
11494        let last_edit_end = insert_anchor.bias_right(buffer);
11495        self.transact(window, cx, |this, window, cx| {
11496            this.buffer.update(cx, |buffer, cx| {
11497                buffer.edit(edits, None, cx);
11498            });
11499            this.change_selections(Default::default(), window, cx, |s| {
11500                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11501            });
11502        });
11503    }
11504
11505    pub fn clear_selection_drag_state(&mut self) {
11506        self.selection_drag_state = SelectionDragState::None;
11507    }
11508
11509    pub fn duplicate(
11510        &mut self,
11511        upwards: bool,
11512        whole_lines: bool,
11513        window: &mut Window,
11514        cx: &mut Context<Self>,
11515    ) {
11516        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11517
11518        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11519        let buffer = display_map.buffer_snapshot();
11520        let selections = self.selections.all::<Point>(&display_map);
11521
11522        let mut edits = Vec::new();
11523        let mut selections_iter = selections.iter().peekable();
11524        while let Some(selection) = selections_iter.next() {
11525            let mut rows = selection.spanned_rows(false, &display_map);
11526            // duplicate line-wise
11527            if whole_lines || selection.start == selection.end {
11528                // Avoid duplicating the same lines twice.
11529                while let Some(next_selection) = selections_iter.peek() {
11530                    let next_rows = next_selection.spanned_rows(false, &display_map);
11531                    if next_rows.start < rows.end {
11532                        rows.end = next_rows.end;
11533                        selections_iter.next().unwrap();
11534                    } else {
11535                        break;
11536                    }
11537                }
11538
11539                // Copy the text from the selected row region and splice it either at the start
11540                // or end of the region.
11541                let start = Point::new(rows.start.0, 0);
11542                let end = Point::new(
11543                    rows.end.previous_row().0,
11544                    buffer.line_len(rows.end.previous_row()),
11545                );
11546
11547                let mut text = buffer.text_for_range(start..end).collect::<String>();
11548
11549                let insert_location = if upwards {
11550                    // When duplicating upward, we need to insert before the current line.
11551                    // If we're on the last line and it doesn't end with a newline,
11552                    // we need to add a newline before the duplicated content.
11553                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11554                        && buffer.max_point().column > 0
11555                        && !text.ends_with('\n');
11556
11557                    if needs_leading_newline {
11558                        text.insert(0, '\n');
11559                        end
11560                    } else {
11561                        text.push('\n');
11562                        Point::new(rows.end.0, 0)
11563                    }
11564                } else {
11565                    text.push('\n');
11566                    start
11567                };
11568                edits.push((insert_location..insert_location, text));
11569            } else {
11570                // duplicate character-wise
11571                let start = selection.start;
11572                let end = selection.end;
11573                let text = buffer.text_for_range(start..end).collect::<String>();
11574                edits.push((selection.end..selection.end, text));
11575            }
11576        }
11577
11578        self.transact(window, cx, |this, _, cx| {
11579            this.buffer.update(cx, |buffer, cx| {
11580                buffer.edit(edits, None, cx);
11581            });
11582
11583            this.request_autoscroll(Autoscroll::fit(), cx);
11584        });
11585    }
11586
11587    pub fn duplicate_line_up(
11588        &mut self,
11589        _: &DuplicateLineUp,
11590        window: &mut Window,
11591        cx: &mut Context<Self>,
11592    ) {
11593        self.duplicate(true, true, window, cx);
11594    }
11595
11596    pub fn duplicate_line_down(
11597        &mut self,
11598        _: &DuplicateLineDown,
11599        window: &mut Window,
11600        cx: &mut Context<Self>,
11601    ) {
11602        self.duplicate(false, true, window, cx);
11603    }
11604
11605    pub fn duplicate_selection(
11606        &mut self,
11607        _: &DuplicateSelection,
11608        window: &mut Window,
11609        cx: &mut Context<Self>,
11610    ) {
11611        self.duplicate(false, false, window, cx);
11612    }
11613
11614    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11615        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11616        if self.mode.is_single_line() {
11617            cx.propagate();
11618            return;
11619        }
11620
11621        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11622        let buffer = self.buffer.read(cx).snapshot(cx);
11623
11624        let mut edits = Vec::new();
11625        let mut unfold_ranges = Vec::new();
11626        let mut refold_creases = Vec::new();
11627
11628        let selections = self.selections.all::<Point>(&display_map);
11629        let mut selections = selections.iter().peekable();
11630        let mut contiguous_row_selections = Vec::new();
11631        let mut new_selections = Vec::new();
11632
11633        while let Some(selection) = selections.next() {
11634            // Find all the selections that span a contiguous row range
11635            let (start_row, end_row) = consume_contiguous_rows(
11636                &mut contiguous_row_selections,
11637                selection,
11638                &display_map,
11639                &mut selections,
11640            );
11641
11642            // Move the text spanned by the row range to be before the line preceding the row range
11643            if start_row.0 > 0 {
11644                let range_to_move = Point::new(
11645                    start_row.previous_row().0,
11646                    buffer.line_len(start_row.previous_row()),
11647                )
11648                    ..Point::new(
11649                        end_row.previous_row().0,
11650                        buffer.line_len(end_row.previous_row()),
11651                    );
11652                let insertion_point = display_map
11653                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11654                    .0;
11655
11656                // Don't move lines across excerpts
11657                if buffer
11658                    .excerpt_containing(insertion_point..range_to_move.end)
11659                    .is_some()
11660                {
11661                    let text = buffer
11662                        .text_for_range(range_to_move.clone())
11663                        .flat_map(|s| s.chars())
11664                        .skip(1)
11665                        .chain(['\n'])
11666                        .collect::<String>();
11667
11668                    edits.push((
11669                        buffer.anchor_after(range_to_move.start)
11670                            ..buffer.anchor_before(range_to_move.end),
11671                        String::new(),
11672                    ));
11673                    let insertion_anchor = buffer.anchor_after(insertion_point);
11674                    edits.push((insertion_anchor..insertion_anchor, text));
11675
11676                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11677
11678                    // Move selections up
11679                    new_selections.extend(contiguous_row_selections.drain(..).map(
11680                        |mut selection| {
11681                            selection.start.row -= row_delta;
11682                            selection.end.row -= row_delta;
11683                            selection
11684                        },
11685                    ));
11686
11687                    // Move folds up
11688                    unfold_ranges.push(range_to_move.clone());
11689                    for fold in display_map.folds_in_range(
11690                        buffer.anchor_before(range_to_move.start)
11691                            ..buffer.anchor_after(range_to_move.end),
11692                    ) {
11693                        let mut start = fold.range.start.to_point(&buffer);
11694                        let mut end = fold.range.end.to_point(&buffer);
11695                        start.row -= row_delta;
11696                        end.row -= row_delta;
11697                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11698                    }
11699                }
11700            }
11701
11702            // If we didn't move line(s), preserve the existing selections
11703            new_selections.append(&mut contiguous_row_selections);
11704        }
11705
11706        self.transact(window, cx, |this, window, cx| {
11707            this.unfold_ranges(&unfold_ranges, true, true, cx);
11708            this.buffer.update(cx, |buffer, cx| {
11709                for (range, text) in edits {
11710                    buffer.edit([(range, text)], None, cx);
11711                }
11712            });
11713            this.fold_creases(refold_creases, true, window, cx);
11714            this.change_selections(Default::default(), window, cx, |s| {
11715                s.select(new_selections);
11716            })
11717        });
11718    }
11719
11720    pub fn move_line_down(
11721        &mut self,
11722        _: &MoveLineDown,
11723        window: &mut Window,
11724        cx: &mut Context<Self>,
11725    ) {
11726        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11727        if self.mode.is_single_line() {
11728            cx.propagate();
11729            return;
11730        }
11731
11732        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11733        let buffer = self.buffer.read(cx).snapshot(cx);
11734
11735        let mut edits = Vec::new();
11736        let mut unfold_ranges = Vec::new();
11737        let mut refold_creases = Vec::new();
11738
11739        let selections = self.selections.all::<Point>(&display_map);
11740        let mut selections = selections.iter().peekable();
11741        let mut contiguous_row_selections = Vec::new();
11742        let mut new_selections = Vec::new();
11743
11744        while let Some(selection) = selections.next() {
11745            // Find all the selections that span a contiguous row range
11746            let (start_row, end_row) = consume_contiguous_rows(
11747                &mut contiguous_row_selections,
11748                selection,
11749                &display_map,
11750                &mut selections,
11751            );
11752
11753            // Move the text spanned by the row range to be after the last line of the row range
11754            if end_row.0 <= buffer.max_point().row {
11755                let range_to_move =
11756                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11757                let insertion_point = display_map
11758                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11759                    .0;
11760
11761                // Don't move lines across excerpt boundaries
11762                if buffer
11763                    .excerpt_containing(range_to_move.start..insertion_point)
11764                    .is_some()
11765                {
11766                    let mut text = String::from("\n");
11767                    text.extend(buffer.text_for_range(range_to_move.clone()));
11768                    text.pop(); // Drop trailing newline
11769                    edits.push((
11770                        buffer.anchor_after(range_to_move.start)
11771                            ..buffer.anchor_before(range_to_move.end),
11772                        String::new(),
11773                    ));
11774                    let insertion_anchor = buffer.anchor_after(insertion_point);
11775                    edits.push((insertion_anchor..insertion_anchor, text));
11776
11777                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11778
11779                    // Move selections down
11780                    new_selections.extend(contiguous_row_selections.drain(..).map(
11781                        |mut selection| {
11782                            selection.start.row += row_delta;
11783                            selection.end.row += row_delta;
11784                            selection
11785                        },
11786                    ));
11787
11788                    // Move folds down
11789                    unfold_ranges.push(range_to_move.clone());
11790                    for fold in display_map.folds_in_range(
11791                        buffer.anchor_before(range_to_move.start)
11792                            ..buffer.anchor_after(range_to_move.end),
11793                    ) {
11794                        let mut start = fold.range.start.to_point(&buffer);
11795                        let mut end = fold.range.end.to_point(&buffer);
11796                        start.row += row_delta;
11797                        end.row += row_delta;
11798                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11799                    }
11800                }
11801            }
11802
11803            // If we didn't move line(s), preserve the existing selections
11804            new_selections.append(&mut contiguous_row_selections);
11805        }
11806
11807        self.transact(window, cx, |this, window, cx| {
11808            this.unfold_ranges(&unfold_ranges, true, true, cx);
11809            this.buffer.update(cx, |buffer, cx| {
11810                for (range, text) in edits {
11811                    buffer.edit([(range, text)], None, cx);
11812                }
11813            });
11814            this.fold_creases(refold_creases, true, window, cx);
11815            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11816        });
11817    }
11818
11819    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11820        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11821        let text_layout_details = &self.text_layout_details(window);
11822        self.transact(window, cx, |this, window, cx| {
11823            let edits = this.change_selections(Default::default(), window, cx, |s| {
11824                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11825                s.move_with(|display_map, selection| {
11826                    if !selection.is_empty() {
11827                        return;
11828                    }
11829
11830                    let mut head = selection.head();
11831                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11832                    if head.column() == display_map.line_len(head.row()) {
11833                        transpose_offset = display_map
11834                            .buffer_snapshot()
11835                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11836                    }
11837
11838                    if transpose_offset == 0 {
11839                        return;
11840                    }
11841
11842                    *head.column_mut() += 1;
11843                    head = display_map.clip_point(head, Bias::Right);
11844                    let goal = SelectionGoal::HorizontalPosition(
11845                        display_map
11846                            .x_for_display_point(head, text_layout_details)
11847                            .into(),
11848                    );
11849                    selection.collapse_to(head, goal);
11850
11851                    let transpose_start = display_map
11852                        .buffer_snapshot()
11853                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11854                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11855                        let transpose_end = display_map
11856                            .buffer_snapshot()
11857                            .clip_offset(transpose_offset + 1, Bias::Right);
11858                        if let Some(ch) = display_map
11859                            .buffer_snapshot()
11860                            .chars_at(transpose_start)
11861                            .next()
11862                        {
11863                            edits.push((transpose_start..transpose_offset, String::new()));
11864                            edits.push((transpose_end..transpose_end, ch.to_string()));
11865                        }
11866                    }
11867                });
11868                edits
11869            });
11870            this.buffer
11871                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11872            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
11873            this.change_selections(Default::default(), window, cx, |s| {
11874                s.select(selections);
11875            });
11876        });
11877    }
11878
11879    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11880        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11881        if self.mode.is_single_line() {
11882            cx.propagate();
11883            return;
11884        }
11885
11886        self.rewrap_impl(RewrapOptions::default(), cx)
11887    }
11888
11889    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11890        let buffer = self.buffer.read(cx).snapshot(cx);
11891        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
11892
11893        #[derive(Clone, Debug, PartialEq)]
11894        enum CommentFormat {
11895            /// single line comment, with prefix for line
11896            Line(String),
11897            /// single line within a block comment, with prefix for line
11898            BlockLine(String),
11899            /// a single line of a block comment that includes the initial delimiter
11900            BlockCommentWithStart(BlockCommentConfig),
11901            /// a single line of a block comment that includes the ending delimiter
11902            BlockCommentWithEnd(BlockCommentConfig),
11903        }
11904
11905        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11906        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11907            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11908                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11909                .peekable();
11910
11911            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11912                row
11913            } else {
11914                return Vec::new();
11915            };
11916
11917            let language_settings = buffer.language_settings_at(selection.head(), cx);
11918            let language_scope = buffer.language_scope_at(selection.head());
11919
11920            let indent_and_prefix_for_row =
11921                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11922                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11923                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11924                        &language_scope
11925                    {
11926                        let indent_end = Point::new(row, indent.len);
11927                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11928                        let line_text_after_indent = buffer
11929                            .text_for_range(indent_end..line_end)
11930                            .collect::<String>();
11931
11932                        let is_within_comment_override = buffer
11933                            .language_scope_at(indent_end)
11934                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11935                        let comment_delimiters = if is_within_comment_override {
11936                            // we are within a comment syntax node, but we don't
11937                            // yet know what kind of comment: block, doc or line
11938                            match (
11939                                language_scope.documentation_comment(),
11940                                language_scope.block_comment(),
11941                            ) {
11942                                (Some(config), _) | (_, Some(config))
11943                                    if buffer.contains_str_at(indent_end, &config.start) =>
11944                                {
11945                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11946                                }
11947                                (Some(config), _) | (_, Some(config))
11948                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11949                                {
11950                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11951                                }
11952                                (Some(config), _) | (_, Some(config))
11953                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11954                                {
11955                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11956                                }
11957                                (_, _) => language_scope
11958                                    .line_comment_prefixes()
11959                                    .iter()
11960                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11961                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11962                            }
11963                        } else {
11964                            // we not in an overridden comment node, but we may
11965                            // be within a non-overridden line comment node
11966                            language_scope
11967                                .line_comment_prefixes()
11968                                .iter()
11969                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11970                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11971                        };
11972
11973                        let rewrap_prefix = language_scope
11974                            .rewrap_prefixes()
11975                            .iter()
11976                            .find_map(|prefix_regex| {
11977                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11978                                    if mat.start() == 0 {
11979                                        Some(mat.as_str().to_string())
11980                                    } else {
11981                                        None
11982                                    }
11983                                })
11984                            })
11985                            .flatten();
11986                        (comment_delimiters, rewrap_prefix)
11987                    } else {
11988                        (None, None)
11989                    };
11990                    (indent, comment_prefix, rewrap_prefix)
11991                };
11992
11993            let mut ranges = Vec::new();
11994            let from_empty_selection = selection.is_empty();
11995
11996            let mut current_range_start = first_row;
11997            let mut prev_row = first_row;
11998            let (
11999                mut current_range_indent,
12000                mut current_range_comment_delimiters,
12001                mut current_range_rewrap_prefix,
12002            ) = indent_and_prefix_for_row(first_row);
12003
12004            for row in non_blank_rows_iter.skip(1) {
12005                let has_paragraph_break = row > prev_row + 1;
12006
12007                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12008                    indent_and_prefix_for_row(row);
12009
12010                let has_indent_change = row_indent != current_range_indent;
12011                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12012
12013                let has_boundary_change = has_comment_change
12014                    || row_rewrap_prefix.is_some()
12015                    || (has_indent_change && current_range_comment_delimiters.is_some());
12016
12017                if has_paragraph_break || has_boundary_change {
12018                    ranges.push((
12019                        language_settings.clone(),
12020                        Point::new(current_range_start, 0)
12021                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12022                        current_range_indent,
12023                        current_range_comment_delimiters.clone(),
12024                        current_range_rewrap_prefix.clone(),
12025                        from_empty_selection,
12026                    ));
12027                    current_range_start = row;
12028                    current_range_indent = row_indent;
12029                    current_range_comment_delimiters = row_comment_delimiters;
12030                    current_range_rewrap_prefix = row_rewrap_prefix;
12031                }
12032                prev_row = row;
12033            }
12034
12035            ranges.push((
12036                language_settings.clone(),
12037                Point::new(current_range_start, 0)
12038                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12039                current_range_indent,
12040                current_range_comment_delimiters,
12041                current_range_rewrap_prefix,
12042                from_empty_selection,
12043            ));
12044
12045            ranges
12046        });
12047
12048        let mut edits = Vec::new();
12049        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12050
12051        for (
12052            language_settings,
12053            wrap_range,
12054            mut indent_size,
12055            comment_prefix,
12056            rewrap_prefix,
12057            from_empty_selection,
12058        ) in wrap_ranges
12059        {
12060            let mut start_row = wrap_range.start.row;
12061            let mut end_row = wrap_range.end.row;
12062
12063            // Skip selections that overlap with a range that has already been rewrapped.
12064            let selection_range = start_row..end_row;
12065            if rewrapped_row_ranges
12066                .iter()
12067                .any(|range| range.overlaps(&selection_range))
12068            {
12069                continue;
12070            }
12071
12072            let tab_size = language_settings.tab_size;
12073
12074            let (line_prefix, inside_comment) = match &comment_prefix {
12075                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12076                    (Some(prefix.as_str()), true)
12077                }
12078                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12079                    (Some(prefix.as_ref()), true)
12080                }
12081                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12082                    start: _,
12083                    end: _,
12084                    prefix,
12085                    tab_size,
12086                })) => {
12087                    indent_size.len += tab_size;
12088                    (Some(prefix.as_ref()), true)
12089                }
12090                None => (None, false),
12091            };
12092            let indent_prefix = indent_size.chars().collect::<String>();
12093            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12094
12095            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12096                RewrapBehavior::InComments => inside_comment,
12097                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12098                RewrapBehavior::Anywhere => true,
12099            };
12100
12101            let should_rewrap = options.override_language_settings
12102                || allow_rewrap_based_on_language
12103                || self.hard_wrap.is_some();
12104            if !should_rewrap {
12105                continue;
12106            }
12107
12108            if from_empty_selection {
12109                'expand_upwards: while start_row > 0 {
12110                    let prev_row = start_row - 1;
12111                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12112                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12113                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12114                    {
12115                        start_row = prev_row;
12116                    } else {
12117                        break 'expand_upwards;
12118                    }
12119                }
12120
12121                'expand_downwards: while end_row < buffer.max_point().row {
12122                    let next_row = end_row + 1;
12123                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12124                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12125                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12126                    {
12127                        end_row = next_row;
12128                    } else {
12129                        break 'expand_downwards;
12130                    }
12131                }
12132            }
12133
12134            let start = Point::new(start_row, 0);
12135            let start_offset = ToOffset::to_offset(&start, &buffer);
12136            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12137            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12138            let mut first_line_delimiter = None;
12139            let mut last_line_delimiter = None;
12140            let Some(lines_without_prefixes) = selection_text
12141                .lines()
12142                .enumerate()
12143                .map(|(ix, line)| {
12144                    let line_trimmed = line.trim_start();
12145                    if rewrap_prefix.is_some() && ix > 0 {
12146                        Ok(line_trimmed)
12147                    } else if let Some(
12148                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12149                            start,
12150                            prefix,
12151                            end,
12152                            tab_size,
12153                        })
12154                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12155                            start,
12156                            prefix,
12157                            end,
12158                            tab_size,
12159                        }),
12160                    ) = &comment_prefix
12161                    {
12162                        let line_trimmed = line_trimmed
12163                            .strip_prefix(start.as_ref())
12164                            .map(|s| {
12165                                let mut indent_size = indent_size;
12166                                indent_size.len -= tab_size;
12167                                let indent_prefix: String = indent_size.chars().collect();
12168                                first_line_delimiter = Some((indent_prefix, start));
12169                                s.trim_start()
12170                            })
12171                            .unwrap_or(line_trimmed);
12172                        let line_trimmed = line_trimmed
12173                            .strip_suffix(end.as_ref())
12174                            .map(|s| {
12175                                last_line_delimiter = Some(end);
12176                                s.trim_end()
12177                            })
12178                            .unwrap_or(line_trimmed);
12179                        let line_trimmed = line_trimmed
12180                            .strip_prefix(prefix.as_ref())
12181                            .unwrap_or(line_trimmed);
12182                        Ok(line_trimmed)
12183                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12184                        line_trimmed.strip_prefix(prefix).with_context(|| {
12185                            format!("line did not start with prefix {prefix:?}: {line:?}")
12186                        })
12187                    } else {
12188                        line_trimmed
12189                            .strip_prefix(&line_prefix.trim_start())
12190                            .with_context(|| {
12191                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12192                            })
12193                    }
12194                })
12195                .collect::<Result<Vec<_>, _>>()
12196                .log_err()
12197            else {
12198                continue;
12199            };
12200
12201            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12202                buffer
12203                    .language_settings_at(Point::new(start_row, 0), cx)
12204                    .preferred_line_length as usize
12205            });
12206
12207            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12208                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12209            } else {
12210                line_prefix.clone()
12211            };
12212
12213            let wrapped_text = {
12214                let mut wrapped_text = wrap_with_prefix(
12215                    line_prefix,
12216                    subsequent_lines_prefix,
12217                    lines_without_prefixes.join("\n"),
12218                    wrap_column,
12219                    tab_size,
12220                    options.preserve_existing_whitespace,
12221                );
12222
12223                if let Some((indent, delimiter)) = first_line_delimiter {
12224                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12225                }
12226                if let Some(last_line) = last_line_delimiter {
12227                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12228                }
12229
12230                wrapped_text
12231            };
12232
12233            // TODO: should always use char-based diff while still supporting cursor behavior that
12234            // matches vim.
12235            let mut diff_options = DiffOptions::default();
12236            if options.override_language_settings {
12237                diff_options.max_word_diff_len = 0;
12238                diff_options.max_word_diff_line_count = 0;
12239            } else {
12240                diff_options.max_word_diff_len = usize::MAX;
12241                diff_options.max_word_diff_line_count = usize::MAX;
12242            }
12243
12244            for (old_range, new_text) in
12245                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12246            {
12247                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12248                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12249                edits.push((edit_start..edit_end, new_text));
12250            }
12251
12252            rewrapped_row_ranges.push(start_row..=end_row);
12253        }
12254
12255        self.buffer
12256            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12257    }
12258
12259    pub fn cut_common(
12260        &mut self,
12261        cut_no_selection_line: bool,
12262        window: &mut Window,
12263        cx: &mut Context<Self>,
12264    ) -> ClipboardItem {
12265        let mut text = String::new();
12266        let buffer = self.buffer.read(cx).snapshot(cx);
12267        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12268        let mut clipboard_selections = Vec::with_capacity(selections.len());
12269        {
12270            let max_point = buffer.max_point();
12271            let mut is_first = true;
12272            for selection in &mut selections {
12273                let is_entire_line =
12274                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12275                if is_entire_line {
12276                    selection.start = Point::new(selection.start.row, 0);
12277                    if !selection.is_empty() && selection.end.column == 0 {
12278                        selection.end = cmp::min(max_point, selection.end);
12279                    } else {
12280                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12281                    }
12282                    selection.goal = SelectionGoal::None;
12283                }
12284                if is_first {
12285                    is_first = false;
12286                } else {
12287                    text += "\n";
12288                }
12289                let mut len = 0;
12290                for chunk in buffer.text_for_range(selection.start..selection.end) {
12291                    text.push_str(chunk);
12292                    len += chunk.len();
12293                }
12294                clipboard_selections.push(ClipboardSelection {
12295                    len,
12296                    is_entire_line,
12297                    first_line_indent: buffer
12298                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12299                        .len,
12300                });
12301            }
12302        }
12303
12304        self.transact(window, cx, |this, window, cx| {
12305            this.change_selections(Default::default(), window, cx, |s| {
12306                s.select(selections);
12307            });
12308            this.insert("", window, cx);
12309        });
12310        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12311    }
12312
12313    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12314        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12315        let item = self.cut_common(true, window, cx);
12316        cx.write_to_clipboard(item);
12317    }
12318
12319    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12320        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12321        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12322            s.move_with(|snapshot, sel| {
12323                if sel.is_empty() {
12324                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12325                }
12326                if sel.is_empty() {
12327                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12328                }
12329            });
12330        });
12331        let item = self.cut_common(false, window, cx);
12332        cx.set_global(KillRing(item))
12333    }
12334
12335    pub fn kill_ring_yank(
12336        &mut self,
12337        _: &KillRingYank,
12338        window: &mut Window,
12339        cx: &mut Context<Self>,
12340    ) {
12341        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12342        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12343            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12344                (kill_ring.text().to_string(), kill_ring.metadata_json())
12345            } else {
12346                return;
12347            }
12348        } else {
12349            return;
12350        };
12351        self.do_paste(&text, metadata, false, window, cx);
12352    }
12353
12354    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12355        self.do_copy(true, cx);
12356    }
12357
12358    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12359        self.do_copy(false, cx);
12360    }
12361
12362    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12363        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12364        let buffer = self.buffer.read(cx).read(cx);
12365        let mut text = String::new();
12366
12367        let mut clipboard_selections = Vec::with_capacity(selections.len());
12368        {
12369            let max_point = buffer.max_point();
12370            let mut is_first = true;
12371            for selection in &selections {
12372                let mut start = selection.start;
12373                let mut end = selection.end;
12374                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12375                let mut add_trailing_newline = false;
12376                if is_entire_line {
12377                    start = Point::new(start.row, 0);
12378                    let next_line_start = Point::new(end.row + 1, 0);
12379                    if next_line_start <= max_point {
12380                        end = next_line_start;
12381                    } else {
12382                        // We're on the last line without a trailing newline.
12383                        // Copy to the end of the line and add a newline afterwards.
12384                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12385                        add_trailing_newline = true;
12386                    }
12387                }
12388
12389                let mut trimmed_selections = Vec::new();
12390                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12391                    let row = MultiBufferRow(start.row);
12392                    let first_indent = buffer.indent_size_for_line(row);
12393                    if first_indent.len == 0 || start.column > first_indent.len {
12394                        trimmed_selections.push(start..end);
12395                    } else {
12396                        trimmed_selections.push(
12397                            Point::new(row.0, first_indent.len)
12398                                ..Point::new(row.0, buffer.line_len(row)),
12399                        );
12400                        for row in start.row + 1..=end.row {
12401                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12402                            if row == end.row {
12403                                line_len = end.column;
12404                            }
12405                            if line_len == 0 {
12406                                trimmed_selections
12407                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12408                                continue;
12409                            }
12410                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12411                            if row_indent_size.len >= first_indent.len {
12412                                trimmed_selections.push(
12413                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12414                                );
12415                            } else {
12416                                trimmed_selections.clear();
12417                                trimmed_selections.push(start..end);
12418                                break;
12419                            }
12420                        }
12421                    }
12422                } else {
12423                    trimmed_selections.push(start..end);
12424                }
12425
12426                for trimmed_range in trimmed_selections {
12427                    if is_first {
12428                        is_first = false;
12429                    } else {
12430                        text += "\n";
12431                    }
12432                    let mut len = 0;
12433                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12434                        text.push_str(chunk);
12435                        len += chunk.len();
12436                    }
12437                    if add_trailing_newline {
12438                        text.push('\n');
12439                        len += 1;
12440                    }
12441                    clipboard_selections.push(ClipboardSelection {
12442                        len,
12443                        is_entire_line,
12444                        first_line_indent: buffer
12445                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12446                            .len,
12447                    });
12448                }
12449            }
12450        }
12451
12452        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12453            text,
12454            clipboard_selections,
12455        ));
12456    }
12457
12458    pub fn do_paste(
12459        &mut self,
12460        text: &String,
12461        clipboard_selections: Option<Vec<ClipboardSelection>>,
12462        handle_entire_lines: bool,
12463        window: &mut Window,
12464        cx: &mut Context<Self>,
12465    ) {
12466        if self.read_only(cx) {
12467            return;
12468        }
12469
12470        let clipboard_text = Cow::Borrowed(text.as_str());
12471
12472        self.transact(window, cx, |this, window, cx| {
12473            let had_active_edit_prediction = this.has_active_edit_prediction();
12474            let display_map = this.display_snapshot(cx);
12475            let old_selections = this.selections.all::<usize>(&display_map);
12476            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12477
12478            if let Some(mut clipboard_selections) = clipboard_selections {
12479                let all_selections_were_entire_line =
12480                    clipboard_selections.iter().all(|s| s.is_entire_line);
12481                let first_selection_indent_column =
12482                    clipboard_selections.first().map(|s| s.first_line_indent);
12483                if clipboard_selections.len() != old_selections.len() {
12484                    clipboard_selections.drain(..);
12485                }
12486                let mut auto_indent_on_paste = true;
12487
12488                this.buffer.update(cx, |buffer, cx| {
12489                    let snapshot = buffer.read(cx);
12490                    auto_indent_on_paste = snapshot
12491                        .language_settings_at(cursor_offset, cx)
12492                        .auto_indent_on_paste;
12493
12494                    let mut start_offset = 0;
12495                    let mut edits = Vec::new();
12496                    let mut original_indent_columns = Vec::new();
12497                    for (ix, selection) in old_selections.iter().enumerate() {
12498                        let to_insert;
12499                        let entire_line;
12500                        let original_indent_column;
12501                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12502                            let end_offset = start_offset + clipboard_selection.len;
12503                            to_insert = &clipboard_text[start_offset..end_offset];
12504                            entire_line = clipboard_selection.is_entire_line;
12505                            start_offset = end_offset + 1;
12506                            original_indent_column = Some(clipboard_selection.first_line_indent);
12507                        } else {
12508                            to_insert = &*clipboard_text;
12509                            entire_line = all_selections_were_entire_line;
12510                            original_indent_column = first_selection_indent_column
12511                        }
12512
12513                        let (range, to_insert) =
12514                            if selection.is_empty() && handle_entire_lines && entire_line {
12515                                // If the corresponding selection was empty when this slice of the
12516                                // clipboard text was written, then the entire line containing the
12517                                // selection was copied. If this selection is also currently empty,
12518                                // then paste the line before the current line of the buffer.
12519                                let column = selection.start.to_point(&snapshot).column as usize;
12520                                let line_start = selection.start - column;
12521                                (line_start..line_start, Cow::Borrowed(to_insert))
12522                            } else {
12523                                let language = snapshot.language_at(selection.head());
12524                                let range = selection.range();
12525                                if let Some(language) = language
12526                                    && language.name() == "Markdown".into()
12527                                {
12528                                    edit_for_markdown_paste(
12529                                        &snapshot,
12530                                        range,
12531                                        to_insert,
12532                                        url::Url::parse(to_insert).ok(),
12533                                    )
12534                                } else {
12535                                    (range, Cow::Borrowed(to_insert))
12536                                }
12537                            };
12538
12539                        edits.push((range, to_insert));
12540                        original_indent_columns.push(original_indent_column);
12541                    }
12542                    drop(snapshot);
12543
12544                    buffer.edit(
12545                        edits,
12546                        if auto_indent_on_paste {
12547                            Some(AutoindentMode::Block {
12548                                original_indent_columns,
12549                            })
12550                        } else {
12551                            None
12552                        },
12553                        cx,
12554                    );
12555                });
12556
12557                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12558                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12559            } else {
12560                let url = url::Url::parse(&clipboard_text).ok();
12561
12562                let auto_indent_mode = if !clipboard_text.is_empty() {
12563                    Some(AutoindentMode::Block {
12564                        original_indent_columns: Vec::new(),
12565                    })
12566                } else {
12567                    None
12568                };
12569
12570                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12571                    let snapshot = buffer.snapshot(cx);
12572
12573                    let anchors = old_selections
12574                        .iter()
12575                        .map(|s| {
12576                            let anchor = snapshot.anchor_after(s.head());
12577                            s.map(|_| anchor)
12578                        })
12579                        .collect::<Vec<_>>();
12580
12581                    let mut edits = Vec::new();
12582
12583                    for selection in old_selections.iter() {
12584                        let language = snapshot.language_at(selection.head());
12585                        let range = selection.range();
12586
12587                        let (edit_range, edit_text) = if let Some(language) = language
12588                            && language.name() == "Markdown".into()
12589                        {
12590                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12591                        } else {
12592                            (range, clipboard_text.clone())
12593                        };
12594
12595                        edits.push((edit_range, edit_text));
12596                    }
12597
12598                    drop(snapshot);
12599                    buffer.edit(edits, auto_indent_mode, cx);
12600
12601                    anchors
12602                });
12603
12604                this.change_selections(Default::default(), window, cx, |s| {
12605                    s.select_anchors(selection_anchors);
12606                });
12607            }
12608
12609            let trigger_in_words =
12610                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12611
12612            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12613        });
12614    }
12615
12616    pub fn diff_clipboard_with_selection(
12617        &mut self,
12618        _: &DiffClipboardWithSelection,
12619        window: &mut Window,
12620        cx: &mut Context<Self>,
12621    ) {
12622        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12623
12624        if selections.is_empty() {
12625            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12626            return;
12627        };
12628
12629        let clipboard_text = match cx.read_from_clipboard() {
12630            Some(item) => match item.entries().first() {
12631                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12632                _ => None,
12633            },
12634            None => None,
12635        };
12636
12637        let Some(clipboard_text) = clipboard_text else {
12638            log::warn!("Clipboard doesn't contain text.");
12639            return;
12640        };
12641
12642        window.dispatch_action(
12643            Box::new(DiffClipboardWithSelectionData {
12644                clipboard_text,
12645                editor: cx.entity(),
12646            }),
12647            cx,
12648        );
12649    }
12650
12651    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12652        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12653        if let Some(item) = cx.read_from_clipboard() {
12654            let entries = item.entries();
12655
12656            match entries.first() {
12657                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12658                // of all the pasted entries.
12659                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12660                    .do_paste(
12661                        clipboard_string.text(),
12662                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12663                        true,
12664                        window,
12665                        cx,
12666                    ),
12667                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12668            }
12669        }
12670    }
12671
12672    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12673        if self.read_only(cx) {
12674            return;
12675        }
12676
12677        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12678
12679        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12680            if let Some((selections, _)) =
12681                self.selection_history.transaction(transaction_id).cloned()
12682            {
12683                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12684                    s.select_anchors(selections.to_vec());
12685                });
12686            } else {
12687                log::error!(
12688                    "No entry in selection_history found for undo. \
12689                     This may correspond to a bug where undo does not update the selection. \
12690                     If this is occurring, please add details to \
12691                     https://github.com/zed-industries/zed/issues/22692"
12692                );
12693            }
12694            self.request_autoscroll(Autoscroll::fit(), cx);
12695            self.unmark_text(window, cx);
12696            self.refresh_edit_prediction(true, false, window, cx);
12697            cx.emit(EditorEvent::Edited { transaction_id });
12698            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12699        }
12700    }
12701
12702    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12703        if self.read_only(cx) {
12704            return;
12705        }
12706
12707        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12708
12709        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12710            if let Some((_, Some(selections))) =
12711                self.selection_history.transaction(transaction_id).cloned()
12712            {
12713                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12714                    s.select_anchors(selections.to_vec());
12715                });
12716            } else {
12717                log::error!(
12718                    "No entry in selection_history found for redo. \
12719                     This may correspond to a bug where undo does not update the selection. \
12720                     If this is occurring, please add details to \
12721                     https://github.com/zed-industries/zed/issues/22692"
12722                );
12723            }
12724            self.request_autoscroll(Autoscroll::fit(), cx);
12725            self.unmark_text(window, cx);
12726            self.refresh_edit_prediction(true, false, window, cx);
12727            cx.emit(EditorEvent::Edited { transaction_id });
12728        }
12729    }
12730
12731    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12732        self.buffer
12733            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12734    }
12735
12736    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12737        self.buffer
12738            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12739    }
12740
12741    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12742        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12743        self.change_selections(Default::default(), window, cx, |s| {
12744            s.move_with(|map, selection| {
12745                let cursor = if selection.is_empty() {
12746                    movement::left(map, selection.start)
12747                } else {
12748                    selection.start
12749                };
12750                selection.collapse_to(cursor, SelectionGoal::None);
12751            });
12752        })
12753    }
12754
12755    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12756        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12757        self.change_selections(Default::default(), window, cx, |s| {
12758            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12759        })
12760    }
12761
12762    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12763        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12764        self.change_selections(Default::default(), window, cx, |s| {
12765            s.move_with(|map, selection| {
12766                let cursor = if selection.is_empty() {
12767                    movement::right(map, selection.end)
12768                } else {
12769                    selection.end
12770                };
12771                selection.collapse_to(cursor, SelectionGoal::None)
12772            });
12773        })
12774    }
12775
12776    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12778        self.change_selections(Default::default(), window, cx, |s| {
12779            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12780        });
12781    }
12782
12783    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12784        if self.take_rename(true, window, cx).is_some() {
12785            return;
12786        }
12787
12788        if self.mode.is_single_line() {
12789            cx.propagate();
12790            return;
12791        }
12792
12793        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12794
12795        let text_layout_details = &self.text_layout_details(window);
12796        let selection_count = self.selections.count();
12797        let first_selection = self.selections.first_anchor();
12798
12799        self.change_selections(Default::default(), window, cx, |s| {
12800            s.move_with(|map, selection| {
12801                if !selection.is_empty() {
12802                    selection.goal = SelectionGoal::None;
12803                }
12804                let (cursor, goal) = movement::up(
12805                    map,
12806                    selection.start,
12807                    selection.goal,
12808                    false,
12809                    text_layout_details,
12810                );
12811                selection.collapse_to(cursor, goal);
12812            });
12813        });
12814
12815        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12816        {
12817            cx.propagate();
12818        }
12819    }
12820
12821    pub fn move_up_by_lines(
12822        &mut self,
12823        action: &MoveUpByLines,
12824        window: &mut Window,
12825        cx: &mut Context<Self>,
12826    ) {
12827        if self.take_rename(true, window, cx).is_some() {
12828            return;
12829        }
12830
12831        if self.mode.is_single_line() {
12832            cx.propagate();
12833            return;
12834        }
12835
12836        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12837
12838        let text_layout_details = &self.text_layout_details(window);
12839
12840        self.change_selections(Default::default(), window, cx, |s| {
12841            s.move_with(|map, selection| {
12842                if !selection.is_empty() {
12843                    selection.goal = SelectionGoal::None;
12844                }
12845                let (cursor, goal) = movement::up_by_rows(
12846                    map,
12847                    selection.start,
12848                    action.lines,
12849                    selection.goal,
12850                    false,
12851                    text_layout_details,
12852                );
12853                selection.collapse_to(cursor, goal);
12854            });
12855        })
12856    }
12857
12858    pub fn move_down_by_lines(
12859        &mut self,
12860        action: &MoveDownByLines,
12861        window: &mut Window,
12862        cx: &mut Context<Self>,
12863    ) {
12864        if self.take_rename(true, window, cx).is_some() {
12865            return;
12866        }
12867
12868        if self.mode.is_single_line() {
12869            cx.propagate();
12870            return;
12871        }
12872
12873        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12874
12875        let text_layout_details = &self.text_layout_details(window);
12876
12877        self.change_selections(Default::default(), window, cx, |s| {
12878            s.move_with(|map, selection| {
12879                if !selection.is_empty() {
12880                    selection.goal = SelectionGoal::None;
12881                }
12882                let (cursor, goal) = movement::down_by_rows(
12883                    map,
12884                    selection.start,
12885                    action.lines,
12886                    selection.goal,
12887                    false,
12888                    text_layout_details,
12889                );
12890                selection.collapse_to(cursor, goal);
12891            });
12892        })
12893    }
12894
12895    pub fn select_down_by_lines(
12896        &mut self,
12897        action: &SelectDownByLines,
12898        window: &mut Window,
12899        cx: &mut Context<Self>,
12900    ) {
12901        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12902        let text_layout_details = &self.text_layout_details(window);
12903        self.change_selections(Default::default(), window, cx, |s| {
12904            s.move_heads_with(|map, head, goal| {
12905                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12906            })
12907        })
12908    }
12909
12910    pub fn select_up_by_lines(
12911        &mut self,
12912        action: &SelectUpByLines,
12913        window: &mut Window,
12914        cx: &mut Context<Self>,
12915    ) {
12916        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12917        let text_layout_details = &self.text_layout_details(window);
12918        self.change_selections(Default::default(), window, cx, |s| {
12919            s.move_heads_with(|map, head, goal| {
12920                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12921            })
12922        })
12923    }
12924
12925    pub fn select_page_up(
12926        &mut self,
12927        _: &SelectPageUp,
12928        window: &mut Window,
12929        cx: &mut Context<Self>,
12930    ) {
12931        let Some(row_count) = self.visible_row_count() else {
12932            return;
12933        };
12934
12935        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12936
12937        let text_layout_details = &self.text_layout_details(window);
12938
12939        self.change_selections(Default::default(), window, cx, |s| {
12940            s.move_heads_with(|map, head, goal| {
12941                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12942            })
12943        })
12944    }
12945
12946    pub fn move_page_up(
12947        &mut self,
12948        action: &MovePageUp,
12949        window: &mut Window,
12950        cx: &mut Context<Self>,
12951    ) {
12952        if self.take_rename(true, window, cx).is_some() {
12953            return;
12954        }
12955
12956        if self
12957            .context_menu
12958            .borrow_mut()
12959            .as_mut()
12960            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12961            .unwrap_or(false)
12962        {
12963            return;
12964        }
12965
12966        if matches!(self.mode, EditorMode::SingleLine) {
12967            cx.propagate();
12968            return;
12969        }
12970
12971        let Some(row_count) = self.visible_row_count() else {
12972            return;
12973        };
12974
12975        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12976
12977        let effects = if action.center_cursor {
12978            SelectionEffects::scroll(Autoscroll::center())
12979        } else {
12980            SelectionEffects::default()
12981        };
12982
12983        let text_layout_details = &self.text_layout_details(window);
12984
12985        self.change_selections(effects, window, cx, |s| {
12986            s.move_with(|map, selection| {
12987                if !selection.is_empty() {
12988                    selection.goal = SelectionGoal::None;
12989                }
12990                let (cursor, goal) = movement::up_by_rows(
12991                    map,
12992                    selection.end,
12993                    row_count,
12994                    selection.goal,
12995                    false,
12996                    text_layout_details,
12997                );
12998                selection.collapse_to(cursor, goal);
12999            });
13000        });
13001    }
13002
13003    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13004        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13005        let text_layout_details = &self.text_layout_details(window);
13006        self.change_selections(Default::default(), window, cx, |s| {
13007            s.move_heads_with(|map, head, goal| {
13008                movement::up(map, head, goal, false, text_layout_details)
13009            })
13010        })
13011    }
13012
13013    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13014        self.take_rename(true, window, cx);
13015
13016        if self.mode.is_single_line() {
13017            cx.propagate();
13018            return;
13019        }
13020
13021        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13022
13023        let text_layout_details = &self.text_layout_details(window);
13024        let selection_count = self.selections.count();
13025        let first_selection = self.selections.first_anchor();
13026
13027        self.change_selections(Default::default(), window, cx, |s| {
13028            s.move_with(|map, selection| {
13029                if !selection.is_empty() {
13030                    selection.goal = SelectionGoal::None;
13031                }
13032                let (cursor, goal) = movement::down(
13033                    map,
13034                    selection.end,
13035                    selection.goal,
13036                    false,
13037                    text_layout_details,
13038                );
13039                selection.collapse_to(cursor, goal);
13040            });
13041        });
13042
13043        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13044        {
13045            cx.propagate();
13046        }
13047    }
13048
13049    pub fn select_page_down(
13050        &mut self,
13051        _: &SelectPageDown,
13052        window: &mut Window,
13053        cx: &mut Context<Self>,
13054    ) {
13055        let Some(row_count) = self.visible_row_count() else {
13056            return;
13057        };
13058
13059        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13060
13061        let text_layout_details = &self.text_layout_details(window);
13062
13063        self.change_selections(Default::default(), window, cx, |s| {
13064            s.move_heads_with(|map, head, goal| {
13065                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13066            })
13067        })
13068    }
13069
13070    pub fn move_page_down(
13071        &mut self,
13072        action: &MovePageDown,
13073        window: &mut Window,
13074        cx: &mut Context<Self>,
13075    ) {
13076        if self.take_rename(true, window, cx).is_some() {
13077            return;
13078        }
13079
13080        if self
13081            .context_menu
13082            .borrow_mut()
13083            .as_mut()
13084            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13085            .unwrap_or(false)
13086        {
13087            return;
13088        }
13089
13090        if matches!(self.mode, EditorMode::SingleLine) {
13091            cx.propagate();
13092            return;
13093        }
13094
13095        let Some(row_count) = self.visible_row_count() else {
13096            return;
13097        };
13098
13099        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13100
13101        let effects = if action.center_cursor {
13102            SelectionEffects::scroll(Autoscroll::center())
13103        } else {
13104            SelectionEffects::default()
13105        };
13106
13107        let text_layout_details = &self.text_layout_details(window);
13108        self.change_selections(effects, window, cx, |s| {
13109            s.move_with(|map, selection| {
13110                if !selection.is_empty() {
13111                    selection.goal = SelectionGoal::None;
13112                }
13113                let (cursor, goal) = movement::down_by_rows(
13114                    map,
13115                    selection.end,
13116                    row_count,
13117                    selection.goal,
13118                    false,
13119                    text_layout_details,
13120                );
13121                selection.collapse_to(cursor, goal);
13122            });
13123        });
13124    }
13125
13126    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13127        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13128        let text_layout_details = &self.text_layout_details(window);
13129        self.change_selections(Default::default(), window, cx, |s| {
13130            s.move_heads_with(|map, head, goal| {
13131                movement::down(map, head, goal, false, text_layout_details)
13132            })
13133        });
13134    }
13135
13136    pub fn context_menu_first(
13137        &mut self,
13138        _: &ContextMenuFirst,
13139        window: &mut Window,
13140        cx: &mut Context<Self>,
13141    ) {
13142        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13143            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13144        }
13145    }
13146
13147    pub fn context_menu_prev(
13148        &mut self,
13149        _: &ContextMenuPrevious,
13150        window: &mut Window,
13151        cx: &mut Context<Self>,
13152    ) {
13153        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13154            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13155        }
13156    }
13157
13158    pub fn context_menu_next(
13159        &mut self,
13160        _: &ContextMenuNext,
13161        window: &mut Window,
13162        cx: &mut Context<Self>,
13163    ) {
13164        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13165            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13166        }
13167    }
13168
13169    pub fn context_menu_last(
13170        &mut self,
13171        _: &ContextMenuLast,
13172        window: &mut Window,
13173        cx: &mut Context<Self>,
13174    ) {
13175        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13176            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13177        }
13178    }
13179
13180    pub fn signature_help_prev(
13181        &mut self,
13182        _: &SignatureHelpPrevious,
13183        _: &mut Window,
13184        cx: &mut Context<Self>,
13185    ) {
13186        if let Some(popover) = self.signature_help_state.popover_mut() {
13187            if popover.current_signature == 0 {
13188                popover.current_signature = popover.signatures.len() - 1;
13189            } else {
13190                popover.current_signature -= 1;
13191            }
13192            cx.notify();
13193        }
13194    }
13195
13196    pub fn signature_help_next(
13197        &mut self,
13198        _: &SignatureHelpNext,
13199        _: &mut Window,
13200        cx: &mut Context<Self>,
13201    ) {
13202        if let Some(popover) = self.signature_help_state.popover_mut() {
13203            if popover.current_signature + 1 == popover.signatures.len() {
13204                popover.current_signature = 0;
13205            } else {
13206                popover.current_signature += 1;
13207            }
13208            cx.notify();
13209        }
13210    }
13211
13212    pub fn move_to_previous_word_start(
13213        &mut self,
13214        _: &MoveToPreviousWordStart,
13215        window: &mut Window,
13216        cx: &mut Context<Self>,
13217    ) {
13218        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13219        self.change_selections(Default::default(), window, cx, |s| {
13220            s.move_cursors_with(|map, head, _| {
13221                (
13222                    movement::previous_word_start(map, head),
13223                    SelectionGoal::None,
13224                )
13225            });
13226        })
13227    }
13228
13229    pub fn move_to_previous_subword_start(
13230        &mut self,
13231        _: &MoveToPreviousSubwordStart,
13232        window: &mut Window,
13233        cx: &mut Context<Self>,
13234    ) {
13235        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13236        self.change_selections(Default::default(), window, cx, |s| {
13237            s.move_cursors_with(|map, head, _| {
13238                (
13239                    movement::previous_subword_start(map, head),
13240                    SelectionGoal::None,
13241                )
13242            });
13243        })
13244    }
13245
13246    pub fn select_to_previous_word_start(
13247        &mut self,
13248        _: &SelectToPreviousWordStart,
13249        window: &mut Window,
13250        cx: &mut Context<Self>,
13251    ) {
13252        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13253        self.change_selections(Default::default(), window, cx, |s| {
13254            s.move_heads_with(|map, head, _| {
13255                (
13256                    movement::previous_word_start(map, head),
13257                    SelectionGoal::None,
13258                )
13259            });
13260        })
13261    }
13262
13263    pub fn select_to_previous_subword_start(
13264        &mut self,
13265        _: &SelectToPreviousSubwordStart,
13266        window: &mut Window,
13267        cx: &mut Context<Self>,
13268    ) {
13269        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13270        self.change_selections(Default::default(), window, cx, |s| {
13271            s.move_heads_with(|map, head, _| {
13272                (
13273                    movement::previous_subword_start(map, head),
13274                    SelectionGoal::None,
13275                )
13276            });
13277        })
13278    }
13279
13280    pub fn delete_to_previous_word_start(
13281        &mut self,
13282        action: &DeleteToPreviousWordStart,
13283        window: &mut Window,
13284        cx: &mut Context<Self>,
13285    ) {
13286        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13287        self.transact(window, cx, |this, window, cx| {
13288            this.select_autoclose_pair(window, cx);
13289            this.change_selections(Default::default(), window, cx, |s| {
13290                s.move_with(|map, selection| {
13291                    if selection.is_empty() {
13292                        let mut cursor = if action.ignore_newlines {
13293                            movement::previous_word_start(map, selection.head())
13294                        } else {
13295                            movement::previous_word_start_or_newline(map, selection.head())
13296                        };
13297                        cursor = movement::adjust_greedy_deletion(
13298                            map,
13299                            selection.head(),
13300                            cursor,
13301                            action.ignore_brackets,
13302                        );
13303                        selection.set_head(cursor, SelectionGoal::None);
13304                    }
13305                });
13306            });
13307            this.insert("", window, cx);
13308        });
13309    }
13310
13311    pub fn delete_to_previous_subword_start(
13312        &mut self,
13313        _: &DeleteToPreviousSubwordStart,
13314        window: &mut Window,
13315        cx: &mut Context<Self>,
13316    ) {
13317        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13318        self.transact(window, cx, |this, window, cx| {
13319            this.select_autoclose_pair(window, cx);
13320            this.change_selections(Default::default(), window, cx, |s| {
13321                s.move_with(|map, selection| {
13322                    if selection.is_empty() {
13323                        let mut cursor = movement::previous_subword_start(map, selection.head());
13324                        cursor =
13325                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13326                        selection.set_head(cursor, SelectionGoal::None);
13327                    }
13328                });
13329            });
13330            this.insert("", window, cx);
13331        });
13332    }
13333
13334    pub fn move_to_next_word_end(
13335        &mut self,
13336        _: &MoveToNextWordEnd,
13337        window: &mut Window,
13338        cx: &mut Context<Self>,
13339    ) {
13340        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13341        self.change_selections(Default::default(), window, cx, |s| {
13342            s.move_cursors_with(|map, head, _| {
13343                (movement::next_word_end(map, head), SelectionGoal::None)
13344            });
13345        })
13346    }
13347
13348    pub fn move_to_next_subword_end(
13349        &mut self,
13350        _: &MoveToNextSubwordEnd,
13351        window: &mut Window,
13352        cx: &mut Context<Self>,
13353    ) {
13354        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13355        self.change_selections(Default::default(), window, cx, |s| {
13356            s.move_cursors_with(|map, head, _| {
13357                (movement::next_subword_end(map, head), SelectionGoal::None)
13358            });
13359        })
13360    }
13361
13362    pub fn select_to_next_word_end(
13363        &mut self,
13364        _: &SelectToNextWordEnd,
13365        window: &mut Window,
13366        cx: &mut Context<Self>,
13367    ) {
13368        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13369        self.change_selections(Default::default(), window, cx, |s| {
13370            s.move_heads_with(|map, head, _| {
13371                (movement::next_word_end(map, head), SelectionGoal::None)
13372            });
13373        })
13374    }
13375
13376    pub fn select_to_next_subword_end(
13377        &mut self,
13378        _: &SelectToNextSubwordEnd,
13379        window: &mut Window,
13380        cx: &mut Context<Self>,
13381    ) {
13382        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13383        self.change_selections(Default::default(), window, cx, |s| {
13384            s.move_heads_with(|map, head, _| {
13385                (movement::next_subword_end(map, head), SelectionGoal::None)
13386            });
13387        })
13388    }
13389
13390    pub fn delete_to_next_word_end(
13391        &mut self,
13392        action: &DeleteToNextWordEnd,
13393        window: &mut Window,
13394        cx: &mut Context<Self>,
13395    ) {
13396        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13397        self.transact(window, cx, |this, window, cx| {
13398            this.change_selections(Default::default(), window, cx, |s| {
13399                s.move_with(|map, selection| {
13400                    if selection.is_empty() {
13401                        let mut cursor = if action.ignore_newlines {
13402                            movement::next_word_end(map, selection.head())
13403                        } else {
13404                            movement::next_word_end_or_newline(map, selection.head())
13405                        };
13406                        cursor = movement::adjust_greedy_deletion(
13407                            map,
13408                            selection.head(),
13409                            cursor,
13410                            action.ignore_brackets,
13411                        );
13412                        selection.set_head(cursor, SelectionGoal::None);
13413                    }
13414                });
13415            });
13416            this.insert("", window, cx);
13417        });
13418    }
13419
13420    pub fn delete_to_next_subword_end(
13421        &mut self,
13422        _: &DeleteToNextSubwordEnd,
13423        window: &mut Window,
13424        cx: &mut Context<Self>,
13425    ) {
13426        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13427        self.transact(window, cx, |this, window, cx| {
13428            this.change_selections(Default::default(), window, cx, |s| {
13429                s.move_with(|map, selection| {
13430                    if selection.is_empty() {
13431                        let mut cursor = movement::next_subword_end(map, selection.head());
13432                        cursor =
13433                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13434                        selection.set_head(cursor, SelectionGoal::None);
13435                    }
13436                });
13437            });
13438            this.insert("", window, cx);
13439        });
13440    }
13441
13442    pub fn move_to_beginning_of_line(
13443        &mut self,
13444        action: &MoveToBeginningOfLine,
13445        window: &mut Window,
13446        cx: &mut Context<Self>,
13447    ) {
13448        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13449        self.change_selections(Default::default(), window, cx, |s| {
13450            s.move_cursors_with(|map, head, _| {
13451                (
13452                    movement::indented_line_beginning(
13453                        map,
13454                        head,
13455                        action.stop_at_soft_wraps,
13456                        action.stop_at_indent,
13457                    ),
13458                    SelectionGoal::None,
13459                )
13460            });
13461        })
13462    }
13463
13464    pub fn select_to_beginning_of_line(
13465        &mut self,
13466        action: &SelectToBeginningOfLine,
13467        window: &mut Window,
13468        cx: &mut Context<Self>,
13469    ) {
13470        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13471        self.change_selections(Default::default(), window, cx, |s| {
13472            s.move_heads_with(|map, head, _| {
13473                (
13474                    movement::indented_line_beginning(
13475                        map,
13476                        head,
13477                        action.stop_at_soft_wraps,
13478                        action.stop_at_indent,
13479                    ),
13480                    SelectionGoal::None,
13481                )
13482            });
13483        });
13484    }
13485
13486    pub fn delete_to_beginning_of_line(
13487        &mut self,
13488        action: &DeleteToBeginningOfLine,
13489        window: &mut Window,
13490        cx: &mut Context<Self>,
13491    ) {
13492        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13493        self.transact(window, cx, |this, window, cx| {
13494            this.change_selections(Default::default(), window, cx, |s| {
13495                s.move_with(|_, selection| {
13496                    selection.reversed = true;
13497                });
13498            });
13499
13500            this.select_to_beginning_of_line(
13501                &SelectToBeginningOfLine {
13502                    stop_at_soft_wraps: false,
13503                    stop_at_indent: action.stop_at_indent,
13504                },
13505                window,
13506                cx,
13507            );
13508            this.backspace(&Backspace, window, cx);
13509        });
13510    }
13511
13512    pub fn move_to_end_of_line(
13513        &mut self,
13514        action: &MoveToEndOfLine,
13515        window: &mut Window,
13516        cx: &mut Context<Self>,
13517    ) {
13518        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13519        self.change_selections(Default::default(), window, cx, |s| {
13520            s.move_cursors_with(|map, head, _| {
13521                (
13522                    movement::line_end(map, head, action.stop_at_soft_wraps),
13523                    SelectionGoal::None,
13524                )
13525            });
13526        })
13527    }
13528
13529    pub fn select_to_end_of_line(
13530        &mut self,
13531        action: &SelectToEndOfLine,
13532        window: &mut Window,
13533        cx: &mut Context<Self>,
13534    ) {
13535        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13536        self.change_selections(Default::default(), window, cx, |s| {
13537            s.move_heads_with(|map, head, _| {
13538                (
13539                    movement::line_end(map, head, action.stop_at_soft_wraps),
13540                    SelectionGoal::None,
13541                )
13542            });
13543        })
13544    }
13545
13546    pub fn delete_to_end_of_line(
13547        &mut self,
13548        _: &DeleteToEndOfLine,
13549        window: &mut Window,
13550        cx: &mut Context<Self>,
13551    ) {
13552        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13553        self.transact(window, cx, |this, window, cx| {
13554            this.select_to_end_of_line(
13555                &SelectToEndOfLine {
13556                    stop_at_soft_wraps: false,
13557                },
13558                window,
13559                cx,
13560            );
13561            this.delete(&Delete, window, cx);
13562        });
13563    }
13564
13565    pub fn cut_to_end_of_line(
13566        &mut self,
13567        action: &CutToEndOfLine,
13568        window: &mut Window,
13569        cx: &mut Context<Self>,
13570    ) {
13571        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13572        self.transact(window, cx, |this, window, cx| {
13573            this.select_to_end_of_line(
13574                &SelectToEndOfLine {
13575                    stop_at_soft_wraps: false,
13576                },
13577                window,
13578                cx,
13579            );
13580            if !action.stop_at_newlines {
13581                this.change_selections(Default::default(), window, cx, |s| {
13582                    s.move_with(|_, sel| {
13583                        if sel.is_empty() {
13584                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13585                        }
13586                    });
13587                });
13588            }
13589            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13590            let item = this.cut_common(false, window, cx);
13591            cx.write_to_clipboard(item);
13592        });
13593    }
13594
13595    pub fn move_to_start_of_paragraph(
13596        &mut self,
13597        _: &MoveToStartOfParagraph,
13598        window: &mut Window,
13599        cx: &mut Context<Self>,
13600    ) {
13601        if matches!(self.mode, EditorMode::SingleLine) {
13602            cx.propagate();
13603            return;
13604        }
13605        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13606        self.change_selections(Default::default(), window, cx, |s| {
13607            s.move_with(|map, selection| {
13608                selection.collapse_to(
13609                    movement::start_of_paragraph(map, selection.head(), 1),
13610                    SelectionGoal::None,
13611                )
13612            });
13613        })
13614    }
13615
13616    pub fn move_to_end_of_paragraph(
13617        &mut self,
13618        _: &MoveToEndOfParagraph,
13619        window: &mut Window,
13620        cx: &mut Context<Self>,
13621    ) {
13622        if matches!(self.mode, EditorMode::SingleLine) {
13623            cx.propagate();
13624            return;
13625        }
13626        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13627        self.change_selections(Default::default(), window, cx, |s| {
13628            s.move_with(|map, selection| {
13629                selection.collapse_to(
13630                    movement::end_of_paragraph(map, selection.head(), 1),
13631                    SelectionGoal::None,
13632                )
13633            });
13634        })
13635    }
13636
13637    pub fn select_to_start_of_paragraph(
13638        &mut self,
13639        _: &SelectToStartOfParagraph,
13640        window: &mut Window,
13641        cx: &mut Context<Self>,
13642    ) {
13643        if matches!(self.mode, EditorMode::SingleLine) {
13644            cx.propagate();
13645            return;
13646        }
13647        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13648        self.change_selections(Default::default(), window, cx, |s| {
13649            s.move_heads_with(|map, head, _| {
13650                (
13651                    movement::start_of_paragraph(map, head, 1),
13652                    SelectionGoal::None,
13653                )
13654            });
13655        })
13656    }
13657
13658    pub fn select_to_end_of_paragraph(
13659        &mut self,
13660        _: &SelectToEndOfParagraph,
13661        window: &mut Window,
13662        cx: &mut Context<Self>,
13663    ) {
13664        if matches!(self.mode, EditorMode::SingleLine) {
13665            cx.propagate();
13666            return;
13667        }
13668        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13669        self.change_selections(Default::default(), window, cx, |s| {
13670            s.move_heads_with(|map, head, _| {
13671                (
13672                    movement::end_of_paragraph(map, head, 1),
13673                    SelectionGoal::None,
13674                )
13675            });
13676        })
13677    }
13678
13679    pub fn move_to_start_of_excerpt(
13680        &mut self,
13681        _: &MoveToStartOfExcerpt,
13682        window: &mut Window,
13683        cx: &mut Context<Self>,
13684    ) {
13685        if matches!(self.mode, EditorMode::SingleLine) {
13686            cx.propagate();
13687            return;
13688        }
13689        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13690        self.change_selections(Default::default(), window, cx, |s| {
13691            s.move_with(|map, selection| {
13692                selection.collapse_to(
13693                    movement::start_of_excerpt(
13694                        map,
13695                        selection.head(),
13696                        workspace::searchable::Direction::Prev,
13697                    ),
13698                    SelectionGoal::None,
13699                )
13700            });
13701        })
13702    }
13703
13704    pub fn move_to_start_of_next_excerpt(
13705        &mut self,
13706        _: &MoveToStartOfNextExcerpt,
13707        window: &mut Window,
13708        cx: &mut Context<Self>,
13709    ) {
13710        if matches!(self.mode, EditorMode::SingleLine) {
13711            cx.propagate();
13712            return;
13713        }
13714
13715        self.change_selections(Default::default(), window, cx, |s| {
13716            s.move_with(|map, selection| {
13717                selection.collapse_to(
13718                    movement::start_of_excerpt(
13719                        map,
13720                        selection.head(),
13721                        workspace::searchable::Direction::Next,
13722                    ),
13723                    SelectionGoal::None,
13724                )
13725            });
13726        })
13727    }
13728
13729    pub fn move_to_end_of_excerpt(
13730        &mut self,
13731        _: &MoveToEndOfExcerpt,
13732        window: &mut Window,
13733        cx: &mut Context<Self>,
13734    ) {
13735        if matches!(self.mode, EditorMode::SingleLine) {
13736            cx.propagate();
13737            return;
13738        }
13739        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13740        self.change_selections(Default::default(), window, cx, |s| {
13741            s.move_with(|map, selection| {
13742                selection.collapse_to(
13743                    movement::end_of_excerpt(
13744                        map,
13745                        selection.head(),
13746                        workspace::searchable::Direction::Next,
13747                    ),
13748                    SelectionGoal::None,
13749                )
13750            });
13751        })
13752    }
13753
13754    pub fn move_to_end_of_previous_excerpt(
13755        &mut self,
13756        _: &MoveToEndOfPreviousExcerpt,
13757        window: &mut Window,
13758        cx: &mut Context<Self>,
13759    ) {
13760        if matches!(self.mode, EditorMode::SingleLine) {
13761            cx.propagate();
13762            return;
13763        }
13764        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13765        self.change_selections(Default::default(), window, cx, |s| {
13766            s.move_with(|map, selection| {
13767                selection.collapse_to(
13768                    movement::end_of_excerpt(
13769                        map,
13770                        selection.head(),
13771                        workspace::searchable::Direction::Prev,
13772                    ),
13773                    SelectionGoal::None,
13774                )
13775            });
13776        })
13777    }
13778
13779    pub fn select_to_start_of_excerpt(
13780        &mut self,
13781        _: &SelectToStartOfExcerpt,
13782        window: &mut Window,
13783        cx: &mut Context<Self>,
13784    ) {
13785        if matches!(self.mode, EditorMode::SingleLine) {
13786            cx.propagate();
13787            return;
13788        }
13789        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13790        self.change_selections(Default::default(), window, cx, |s| {
13791            s.move_heads_with(|map, head, _| {
13792                (
13793                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13794                    SelectionGoal::None,
13795                )
13796            });
13797        })
13798    }
13799
13800    pub fn select_to_start_of_next_excerpt(
13801        &mut self,
13802        _: &SelectToStartOfNextExcerpt,
13803        window: &mut Window,
13804        cx: &mut Context<Self>,
13805    ) {
13806        if matches!(self.mode, EditorMode::SingleLine) {
13807            cx.propagate();
13808            return;
13809        }
13810        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13811        self.change_selections(Default::default(), window, cx, |s| {
13812            s.move_heads_with(|map, head, _| {
13813                (
13814                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13815                    SelectionGoal::None,
13816                )
13817            });
13818        })
13819    }
13820
13821    pub fn select_to_end_of_excerpt(
13822        &mut self,
13823        _: &SelectToEndOfExcerpt,
13824        window: &mut Window,
13825        cx: &mut Context<Self>,
13826    ) {
13827        if matches!(self.mode, EditorMode::SingleLine) {
13828            cx.propagate();
13829            return;
13830        }
13831        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13832        self.change_selections(Default::default(), window, cx, |s| {
13833            s.move_heads_with(|map, head, _| {
13834                (
13835                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13836                    SelectionGoal::None,
13837                )
13838            });
13839        })
13840    }
13841
13842    pub fn select_to_end_of_previous_excerpt(
13843        &mut self,
13844        _: &SelectToEndOfPreviousExcerpt,
13845        window: &mut Window,
13846        cx: &mut Context<Self>,
13847    ) {
13848        if matches!(self.mode, EditorMode::SingleLine) {
13849            cx.propagate();
13850            return;
13851        }
13852        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13853        self.change_selections(Default::default(), window, cx, |s| {
13854            s.move_heads_with(|map, head, _| {
13855                (
13856                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13857                    SelectionGoal::None,
13858                )
13859            });
13860        })
13861    }
13862
13863    pub fn move_to_beginning(
13864        &mut self,
13865        _: &MoveToBeginning,
13866        window: &mut Window,
13867        cx: &mut Context<Self>,
13868    ) {
13869        if matches!(self.mode, EditorMode::SingleLine) {
13870            cx.propagate();
13871            return;
13872        }
13873        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13874        self.change_selections(Default::default(), window, cx, |s| {
13875            s.select_ranges(vec![0..0]);
13876        });
13877    }
13878
13879    pub fn select_to_beginning(
13880        &mut self,
13881        _: &SelectToBeginning,
13882        window: &mut Window,
13883        cx: &mut Context<Self>,
13884    ) {
13885        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
13886        selection.set_head(Point::zero(), SelectionGoal::None);
13887        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13888        self.change_selections(Default::default(), window, cx, |s| {
13889            s.select(vec![selection]);
13890        });
13891    }
13892
13893    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13894        if matches!(self.mode, EditorMode::SingleLine) {
13895            cx.propagate();
13896            return;
13897        }
13898        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13899        let cursor = self.buffer.read(cx).read(cx).len();
13900        self.change_selections(Default::default(), window, cx, |s| {
13901            s.select_ranges(vec![cursor..cursor])
13902        });
13903    }
13904
13905    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13906        self.nav_history = nav_history;
13907    }
13908
13909    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13910        self.nav_history.as_ref()
13911    }
13912
13913    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13914        self.push_to_nav_history(
13915            self.selections.newest_anchor().head(),
13916            None,
13917            false,
13918            true,
13919            cx,
13920        );
13921    }
13922
13923    fn push_to_nav_history(
13924        &mut self,
13925        cursor_anchor: Anchor,
13926        new_position: Option<Point>,
13927        is_deactivate: bool,
13928        always: bool,
13929        cx: &mut Context<Self>,
13930    ) {
13931        if let Some(nav_history) = self.nav_history.as_mut() {
13932            let buffer = self.buffer.read(cx).read(cx);
13933            let cursor_position = cursor_anchor.to_point(&buffer);
13934            let scroll_state = self.scroll_manager.anchor();
13935            let scroll_top_row = scroll_state.top_row(&buffer);
13936            drop(buffer);
13937
13938            if let Some(new_position) = new_position {
13939                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13940                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13941                    return;
13942                }
13943            }
13944
13945            nav_history.push(
13946                Some(NavigationData {
13947                    cursor_anchor,
13948                    cursor_position,
13949                    scroll_anchor: scroll_state,
13950                    scroll_top_row,
13951                }),
13952                cx,
13953            );
13954            cx.emit(EditorEvent::PushedToNavHistory {
13955                anchor: cursor_anchor,
13956                is_deactivate,
13957            })
13958        }
13959    }
13960
13961    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13962        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13963        let buffer = self.buffer.read(cx).snapshot(cx);
13964        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
13965        selection.set_head(buffer.len(), SelectionGoal::None);
13966        self.change_selections(Default::default(), window, cx, |s| {
13967            s.select(vec![selection]);
13968        });
13969    }
13970
13971    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13972        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13973        let end = self.buffer.read(cx).read(cx).len();
13974        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13975            s.select_ranges(vec![0..end]);
13976        });
13977    }
13978
13979    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13980        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13981        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13982        let mut selections = self.selections.all::<Point>(&display_map);
13983        let max_point = display_map.buffer_snapshot().max_point();
13984        for selection in &mut selections {
13985            let rows = selection.spanned_rows(true, &display_map);
13986            selection.start = Point::new(rows.start.0, 0);
13987            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13988            selection.reversed = false;
13989        }
13990        self.change_selections(Default::default(), window, cx, |s| {
13991            s.select(selections);
13992        });
13993    }
13994
13995    pub fn split_selection_into_lines(
13996        &mut self,
13997        action: &SplitSelectionIntoLines,
13998        window: &mut Window,
13999        cx: &mut Context<Self>,
14000    ) {
14001        let selections = self
14002            .selections
14003            .all::<Point>(&self.display_snapshot(cx))
14004            .into_iter()
14005            .map(|selection| selection.start..selection.end)
14006            .collect::<Vec<_>>();
14007        self.unfold_ranges(&selections, true, true, cx);
14008
14009        let mut new_selection_ranges = Vec::new();
14010        {
14011            let buffer = self.buffer.read(cx).read(cx);
14012            for selection in selections {
14013                for row in selection.start.row..selection.end.row {
14014                    let line_start = Point::new(row, 0);
14015                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14016
14017                    if action.keep_selections {
14018                        // Keep the selection range for each line
14019                        let selection_start = if row == selection.start.row {
14020                            selection.start
14021                        } else {
14022                            line_start
14023                        };
14024                        new_selection_ranges.push(selection_start..line_end);
14025                    } else {
14026                        // Collapse to cursor at end of line
14027                        new_selection_ranges.push(line_end..line_end);
14028                    }
14029                }
14030
14031                let is_multiline_selection = selection.start.row != selection.end.row;
14032                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14033                // so this action feels more ergonomic when paired with other selection operations
14034                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14035                if !should_skip_last {
14036                    if action.keep_selections {
14037                        if is_multiline_selection {
14038                            let line_start = Point::new(selection.end.row, 0);
14039                            new_selection_ranges.push(line_start..selection.end);
14040                        } else {
14041                            new_selection_ranges.push(selection.start..selection.end);
14042                        }
14043                    } else {
14044                        new_selection_ranges.push(selection.end..selection.end);
14045                    }
14046                }
14047            }
14048        }
14049        self.change_selections(Default::default(), window, cx, |s| {
14050            s.select_ranges(new_selection_ranges);
14051        });
14052    }
14053
14054    pub fn add_selection_above(
14055        &mut self,
14056        action: &AddSelectionAbove,
14057        window: &mut Window,
14058        cx: &mut Context<Self>,
14059    ) {
14060        self.add_selection(true, action.skip_soft_wrap, window, cx);
14061    }
14062
14063    pub fn add_selection_below(
14064        &mut self,
14065        action: &AddSelectionBelow,
14066        window: &mut Window,
14067        cx: &mut Context<Self>,
14068    ) {
14069        self.add_selection(false, action.skip_soft_wrap, window, cx);
14070    }
14071
14072    fn add_selection(
14073        &mut self,
14074        above: bool,
14075        skip_soft_wrap: bool,
14076        window: &mut Window,
14077        cx: &mut Context<Self>,
14078    ) {
14079        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14080
14081        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14082        let all_selections = self.selections.all::<Point>(&display_map);
14083        let text_layout_details = self.text_layout_details(window);
14084
14085        let (mut columnar_selections, new_selections_to_columnarize) = {
14086            if let Some(state) = self.add_selections_state.as_ref() {
14087                let columnar_selection_ids: HashSet<_> = state
14088                    .groups
14089                    .iter()
14090                    .flat_map(|group| group.stack.iter())
14091                    .copied()
14092                    .collect();
14093
14094                all_selections
14095                    .into_iter()
14096                    .partition(|s| columnar_selection_ids.contains(&s.id))
14097            } else {
14098                (Vec::new(), all_selections)
14099            }
14100        };
14101
14102        let mut state = self
14103            .add_selections_state
14104            .take()
14105            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14106
14107        for selection in new_selections_to_columnarize {
14108            let range = selection.display_range(&display_map).sorted();
14109            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14110            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14111            let positions = start_x.min(end_x)..start_x.max(end_x);
14112            let mut stack = Vec::new();
14113            for row in range.start.row().0..=range.end.row().0 {
14114                if let Some(selection) = self.selections.build_columnar_selection(
14115                    &display_map,
14116                    DisplayRow(row),
14117                    &positions,
14118                    selection.reversed,
14119                    &text_layout_details,
14120                ) {
14121                    stack.push(selection.id);
14122                    columnar_selections.push(selection);
14123                }
14124            }
14125            if !stack.is_empty() {
14126                if above {
14127                    stack.reverse();
14128                }
14129                state.groups.push(AddSelectionsGroup { above, stack });
14130            }
14131        }
14132
14133        let mut final_selections = Vec::new();
14134        let end_row = if above {
14135            DisplayRow(0)
14136        } else {
14137            display_map.max_point().row()
14138        };
14139
14140        let mut last_added_item_per_group = HashMap::default();
14141        for group in state.groups.iter_mut() {
14142            if let Some(last_id) = group.stack.last() {
14143                last_added_item_per_group.insert(*last_id, group);
14144            }
14145        }
14146
14147        for selection in columnar_selections {
14148            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14149                if above == group.above {
14150                    let range = selection.display_range(&display_map).sorted();
14151                    debug_assert_eq!(range.start.row(), range.end.row());
14152                    let mut row = range.start.row();
14153                    let positions =
14154                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14155                            Pixels::from(start)..Pixels::from(end)
14156                        } else {
14157                            let start_x =
14158                                display_map.x_for_display_point(range.start, &text_layout_details);
14159                            let end_x =
14160                                display_map.x_for_display_point(range.end, &text_layout_details);
14161                            start_x.min(end_x)..start_x.max(end_x)
14162                        };
14163
14164                    let mut maybe_new_selection = None;
14165                    let direction = if above { -1 } else { 1 };
14166
14167                    while row != end_row {
14168                        if skip_soft_wrap {
14169                            row = display_map
14170                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14171                                .row();
14172                        } else if above {
14173                            row.0 -= 1;
14174                        } else {
14175                            row.0 += 1;
14176                        }
14177
14178                        if let Some(new_selection) = self.selections.build_columnar_selection(
14179                            &display_map,
14180                            row,
14181                            &positions,
14182                            selection.reversed,
14183                            &text_layout_details,
14184                        ) {
14185                            maybe_new_selection = Some(new_selection);
14186                            break;
14187                        }
14188                    }
14189
14190                    if let Some(new_selection) = maybe_new_selection {
14191                        group.stack.push(new_selection.id);
14192                        if above {
14193                            final_selections.push(new_selection);
14194                            final_selections.push(selection);
14195                        } else {
14196                            final_selections.push(selection);
14197                            final_selections.push(new_selection);
14198                        }
14199                    } else {
14200                        final_selections.push(selection);
14201                    }
14202                } else {
14203                    group.stack.pop();
14204                }
14205            } else {
14206                final_selections.push(selection);
14207            }
14208        }
14209
14210        self.change_selections(Default::default(), window, cx, |s| {
14211            s.select(final_selections);
14212        });
14213
14214        let final_selection_ids: HashSet<_> = self
14215            .selections
14216            .all::<Point>(&display_map)
14217            .iter()
14218            .map(|s| s.id)
14219            .collect();
14220        state.groups.retain_mut(|group| {
14221            // selections might get merged above so we remove invalid items from stacks
14222            group.stack.retain(|id| final_selection_ids.contains(id));
14223
14224            // single selection in stack can be treated as initial state
14225            group.stack.len() > 1
14226        });
14227
14228        if !state.groups.is_empty() {
14229            self.add_selections_state = Some(state);
14230        }
14231    }
14232
14233    fn select_match_ranges(
14234        &mut self,
14235        range: Range<usize>,
14236        reversed: bool,
14237        replace_newest: bool,
14238        auto_scroll: Option<Autoscroll>,
14239        window: &mut Window,
14240        cx: &mut Context<Editor>,
14241    ) {
14242        self.unfold_ranges(
14243            std::slice::from_ref(&range),
14244            false,
14245            auto_scroll.is_some(),
14246            cx,
14247        );
14248        let effects = if let Some(scroll) = auto_scroll {
14249            SelectionEffects::scroll(scroll)
14250        } else {
14251            SelectionEffects::no_scroll()
14252        };
14253        self.change_selections(effects, window, cx, |s| {
14254            if replace_newest {
14255                s.delete(s.newest_anchor().id);
14256            }
14257            if reversed {
14258                s.insert_range(range.end..range.start);
14259            } else {
14260                s.insert_range(range);
14261            }
14262        });
14263    }
14264
14265    pub fn select_next_match_internal(
14266        &mut self,
14267        display_map: &DisplaySnapshot,
14268        replace_newest: bool,
14269        autoscroll: Option<Autoscroll>,
14270        window: &mut Window,
14271        cx: &mut Context<Self>,
14272    ) -> Result<()> {
14273        let buffer = display_map.buffer_snapshot();
14274        let mut selections = self.selections.all::<usize>(&display_map);
14275        if let Some(mut select_next_state) = self.select_next_state.take() {
14276            let query = &select_next_state.query;
14277            if !select_next_state.done {
14278                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14279                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14280                let mut next_selected_range = None;
14281
14282                // Collect and sort selection ranges for efficient overlap checking
14283                let mut selection_ranges: Vec<_> = selections.iter().map(|s| s.range()).collect();
14284                selection_ranges.sort_by_key(|r| r.start);
14285
14286                let bytes_after_last_selection =
14287                    buffer.bytes_in_range(last_selection.end..buffer.len());
14288                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14289                let query_matches = query
14290                    .stream_find_iter(bytes_after_last_selection)
14291                    .map(|result| (last_selection.end, result))
14292                    .chain(
14293                        query
14294                            .stream_find_iter(bytes_before_first_selection)
14295                            .map(|result| (0, result)),
14296                    );
14297
14298                for (start_offset, query_match) in query_matches {
14299                    let query_match = query_match.unwrap(); // can only fail due to I/O
14300                    let offset_range =
14301                        start_offset + query_match.start()..start_offset + query_match.end();
14302
14303                    if !select_next_state.wordwise
14304                        || (!buffer.is_inside_word(offset_range.start, None)
14305                            && !buffer.is_inside_word(offset_range.end, None))
14306                    {
14307                        // Use binary search to check for overlap (O(log n))
14308                        let overlaps = selection_ranges
14309                            .binary_search_by(|range| {
14310                                if range.end <= offset_range.start {
14311                                    std::cmp::Ordering::Less
14312                                } else if range.start >= offset_range.end {
14313                                    std::cmp::Ordering::Greater
14314                                } else {
14315                                    std::cmp::Ordering::Equal
14316                                }
14317                            })
14318                            .is_ok();
14319
14320                        if !overlaps {
14321                            next_selected_range = Some(offset_range);
14322                            break;
14323                        }
14324                    }
14325                }
14326
14327                if let Some(next_selected_range) = next_selected_range {
14328                    self.select_match_ranges(
14329                        next_selected_range,
14330                        last_selection.reversed,
14331                        replace_newest,
14332                        autoscroll,
14333                        window,
14334                        cx,
14335                    );
14336                } else {
14337                    select_next_state.done = true;
14338                }
14339            }
14340
14341            self.select_next_state = Some(select_next_state);
14342        } else {
14343            let mut only_carets = true;
14344            let mut same_text_selected = true;
14345            let mut selected_text = None;
14346
14347            let mut selections_iter = selections.iter().peekable();
14348            while let Some(selection) = selections_iter.next() {
14349                if selection.start != selection.end {
14350                    only_carets = false;
14351                }
14352
14353                if same_text_selected {
14354                    if selected_text.is_none() {
14355                        selected_text =
14356                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14357                    }
14358
14359                    if let Some(next_selection) = selections_iter.peek() {
14360                        if next_selection.range().len() == selection.range().len() {
14361                            let next_selected_text = buffer
14362                                .text_for_range(next_selection.range())
14363                                .collect::<String>();
14364                            if Some(next_selected_text) != selected_text {
14365                                same_text_selected = false;
14366                                selected_text = None;
14367                            }
14368                        } else {
14369                            same_text_selected = false;
14370                            selected_text = None;
14371                        }
14372                    }
14373                }
14374            }
14375
14376            if only_carets {
14377                for selection in &mut selections {
14378                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14379                    selection.start = word_range.start;
14380                    selection.end = word_range.end;
14381                    selection.goal = SelectionGoal::None;
14382                    selection.reversed = false;
14383                    self.select_match_ranges(
14384                        selection.start..selection.end,
14385                        selection.reversed,
14386                        replace_newest,
14387                        autoscroll,
14388                        window,
14389                        cx,
14390                    );
14391                }
14392
14393                if selections.len() == 1 {
14394                    let selection = selections
14395                        .last()
14396                        .expect("ensured that there's only one selection");
14397                    let query = buffer
14398                        .text_for_range(selection.start..selection.end)
14399                        .collect::<String>();
14400                    let is_empty = query.is_empty();
14401                    let select_state = SelectNextState {
14402                        query: AhoCorasick::new(&[query])?,
14403                        wordwise: true,
14404                        done: is_empty,
14405                    };
14406                    self.select_next_state = Some(select_state);
14407                } else {
14408                    self.select_next_state = None;
14409                }
14410            } else if let Some(selected_text) = selected_text {
14411                self.select_next_state = Some(SelectNextState {
14412                    query: AhoCorasick::new(&[selected_text])?,
14413                    wordwise: false,
14414                    done: false,
14415                });
14416                self.select_next_match_internal(
14417                    display_map,
14418                    replace_newest,
14419                    autoscroll,
14420                    window,
14421                    cx,
14422                )?;
14423            }
14424        }
14425        Ok(())
14426    }
14427
14428    pub fn select_all_matches(
14429        &mut self,
14430        _action: &SelectAllMatches,
14431        window: &mut Window,
14432        cx: &mut Context<Self>,
14433    ) -> Result<()> {
14434        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14435
14436        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14437
14438        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14439        let Some(select_next_state) = self.select_next_state.as_mut() else {
14440            return Ok(());
14441        };
14442        if select_next_state.done {
14443            return Ok(());
14444        }
14445
14446        let mut new_selections = Vec::new();
14447
14448        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14449        let buffer = display_map.buffer_snapshot();
14450        let query_matches = select_next_state
14451            .query
14452            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14453
14454        for query_match in query_matches.into_iter() {
14455            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14456            let offset_range = if reversed {
14457                query_match.end()..query_match.start()
14458            } else {
14459                query_match.start()..query_match.end()
14460            };
14461
14462            if !select_next_state.wordwise
14463                || (!buffer.is_inside_word(offset_range.start, None)
14464                    && !buffer.is_inside_word(offset_range.end, None))
14465            {
14466                new_selections.push(offset_range.start..offset_range.end);
14467            }
14468        }
14469
14470        select_next_state.done = true;
14471
14472        if new_selections.is_empty() {
14473            log::error!("bug: new_selections is empty in select_all_matches");
14474            return Ok(());
14475        }
14476
14477        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14478        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14479            selections.select_ranges(new_selections)
14480        });
14481
14482        Ok(())
14483    }
14484
14485    pub fn select_next(
14486        &mut self,
14487        action: &SelectNext,
14488        window: &mut Window,
14489        cx: &mut Context<Self>,
14490    ) -> Result<()> {
14491        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14492        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14493        self.select_next_match_internal(
14494            &display_map,
14495            action.replace_newest,
14496            Some(Autoscroll::newest()),
14497            window,
14498            cx,
14499        )?;
14500        Ok(())
14501    }
14502
14503    pub fn select_previous(
14504        &mut self,
14505        action: &SelectPrevious,
14506        window: &mut Window,
14507        cx: &mut Context<Self>,
14508    ) -> Result<()> {
14509        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14510        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14511        let buffer = display_map.buffer_snapshot();
14512        let mut selections = self.selections.all::<usize>(&display_map);
14513        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14514            let query = &select_prev_state.query;
14515            if !select_prev_state.done {
14516                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14517                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14518                let mut next_selected_range = None;
14519                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14520                let bytes_before_last_selection =
14521                    buffer.reversed_bytes_in_range(0..last_selection.start);
14522                let bytes_after_first_selection =
14523                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14524                let query_matches = query
14525                    .stream_find_iter(bytes_before_last_selection)
14526                    .map(|result| (last_selection.start, result))
14527                    .chain(
14528                        query
14529                            .stream_find_iter(bytes_after_first_selection)
14530                            .map(|result| (buffer.len(), result)),
14531                    );
14532                for (end_offset, query_match) in query_matches {
14533                    let query_match = query_match.unwrap(); // can only fail due to I/O
14534                    let offset_range =
14535                        end_offset - query_match.end()..end_offset - query_match.start();
14536
14537                    if !select_prev_state.wordwise
14538                        || (!buffer.is_inside_word(offset_range.start, None)
14539                            && !buffer.is_inside_word(offset_range.end, None))
14540                    {
14541                        next_selected_range = Some(offset_range);
14542                        break;
14543                    }
14544                }
14545
14546                if let Some(next_selected_range) = next_selected_range {
14547                    self.select_match_ranges(
14548                        next_selected_range,
14549                        last_selection.reversed,
14550                        action.replace_newest,
14551                        Some(Autoscroll::newest()),
14552                        window,
14553                        cx,
14554                    );
14555                } else {
14556                    select_prev_state.done = true;
14557                }
14558            }
14559
14560            self.select_prev_state = Some(select_prev_state);
14561        } else {
14562            let mut only_carets = true;
14563            let mut same_text_selected = true;
14564            let mut selected_text = None;
14565
14566            let mut selections_iter = selections.iter().peekable();
14567            while let Some(selection) = selections_iter.next() {
14568                if selection.start != selection.end {
14569                    only_carets = false;
14570                }
14571
14572                if same_text_selected {
14573                    if selected_text.is_none() {
14574                        selected_text =
14575                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14576                    }
14577
14578                    if let Some(next_selection) = selections_iter.peek() {
14579                        if next_selection.range().len() == selection.range().len() {
14580                            let next_selected_text = buffer
14581                                .text_for_range(next_selection.range())
14582                                .collect::<String>();
14583                            if Some(next_selected_text) != selected_text {
14584                                same_text_selected = false;
14585                                selected_text = None;
14586                            }
14587                        } else {
14588                            same_text_selected = false;
14589                            selected_text = None;
14590                        }
14591                    }
14592                }
14593            }
14594
14595            if only_carets {
14596                for selection in &mut selections {
14597                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14598                    selection.start = word_range.start;
14599                    selection.end = word_range.end;
14600                    selection.goal = SelectionGoal::None;
14601                    selection.reversed = false;
14602                    self.select_match_ranges(
14603                        selection.start..selection.end,
14604                        selection.reversed,
14605                        action.replace_newest,
14606                        Some(Autoscroll::newest()),
14607                        window,
14608                        cx,
14609                    );
14610                }
14611                if selections.len() == 1 {
14612                    let selection = selections
14613                        .last()
14614                        .expect("ensured that there's only one selection");
14615                    let query = buffer
14616                        .text_for_range(selection.start..selection.end)
14617                        .collect::<String>();
14618                    let is_empty = query.is_empty();
14619                    let select_state = SelectNextState {
14620                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14621                        wordwise: true,
14622                        done: is_empty,
14623                    };
14624                    self.select_prev_state = Some(select_state);
14625                } else {
14626                    self.select_prev_state = None;
14627                }
14628            } else if let Some(selected_text) = selected_text {
14629                self.select_prev_state = Some(SelectNextState {
14630                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14631                    wordwise: false,
14632                    done: false,
14633                });
14634                self.select_previous(action, window, cx)?;
14635            }
14636        }
14637        Ok(())
14638    }
14639
14640    pub fn find_next_match(
14641        &mut self,
14642        _: &FindNextMatch,
14643        window: &mut Window,
14644        cx: &mut Context<Self>,
14645    ) -> Result<()> {
14646        let selections = self.selections.disjoint_anchors_arc();
14647        match selections.first() {
14648            Some(first) if selections.len() >= 2 => {
14649                self.change_selections(Default::default(), window, cx, |s| {
14650                    s.select_ranges([first.range()]);
14651                });
14652            }
14653            _ => self.select_next(
14654                &SelectNext {
14655                    replace_newest: true,
14656                },
14657                window,
14658                cx,
14659            )?,
14660        }
14661        Ok(())
14662    }
14663
14664    pub fn find_previous_match(
14665        &mut self,
14666        _: &FindPreviousMatch,
14667        window: &mut Window,
14668        cx: &mut Context<Self>,
14669    ) -> Result<()> {
14670        let selections = self.selections.disjoint_anchors_arc();
14671        match selections.last() {
14672            Some(last) if selections.len() >= 2 => {
14673                self.change_selections(Default::default(), window, cx, |s| {
14674                    s.select_ranges([last.range()]);
14675                });
14676            }
14677            _ => self.select_previous(
14678                &SelectPrevious {
14679                    replace_newest: true,
14680                },
14681                window,
14682                cx,
14683            )?,
14684        }
14685        Ok(())
14686    }
14687
14688    pub fn toggle_comments(
14689        &mut self,
14690        action: &ToggleComments,
14691        window: &mut Window,
14692        cx: &mut Context<Self>,
14693    ) {
14694        if self.read_only(cx) {
14695            return;
14696        }
14697        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14698        let text_layout_details = &self.text_layout_details(window);
14699        self.transact(window, cx, |this, window, cx| {
14700            let mut selections = this
14701                .selections
14702                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14703            let mut edits = Vec::new();
14704            let mut selection_edit_ranges = Vec::new();
14705            let mut last_toggled_row = None;
14706            let snapshot = this.buffer.read(cx).read(cx);
14707            let empty_str: Arc<str> = Arc::default();
14708            let mut suffixes_inserted = Vec::new();
14709            let ignore_indent = action.ignore_indent;
14710
14711            fn comment_prefix_range(
14712                snapshot: &MultiBufferSnapshot,
14713                row: MultiBufferRow,
14714                comment_prefix: &str,
14715                comment_prefix_whitespace: &str,
14716                ignore_indent: bool,
14717            ) -> Range<Point> {
14718                let indent_size = if ignore_indent {
14719                    0
14720                } else {
14721                    snapshot.indent_size_for_line(row).len
14722                };
14723
14724                let start = Point::new(row.0, indent_size);
14725
14726                let mut line_bytes = snapshot
14727                    .bytes_in_range(start..snapshot.max_point())
14728                    .flatten()
14729                    .copied();
14730
14731                // If this line currently begins with the line comment prefix, then record
14732                // the range containing the prefix.
14733                if line_bytes
14734                    .by_ref()
14735                    .take(comment_prefix.len())
14736                    .eq(comment_prefix.bytes())
14737                {
14738                    // Include any whitespace that matches the comment prefix.
14739                    let matching_whitespace_len = line_bytes
14740                        .zip(comment_prefix_whitespace.bytes())
14741                        .take_while(|(a, b)| a == b)
14742                        .count() as u32;
14743                    let end = Point::new(
14744                        start.row,
14745                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14746                    );
14747                    start..end
14748                } else {
14749                    start..start
14750                }
14751            }
14752
14753            fn comment_suffix_range(
14754                snapshot: &MultiBufferSnapshot,
14755                row: MultiBufferRow,
14756                comment_suffix: &str,
14757                comment_suffix_has_leading_space: bool,
14758            ) -> Range<Point> {
14759                let end = Point::new(row.0, snapshot.line_len(row));
14760                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14761
14762                let mut line_end_bytes = snapshot
14763                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14764                    .flatten()
14765                    .copied();
14766
14767                let leading_space_len = if suffix_start_column > 0
14768                    && line_end_bytes.next() == Some(b' ')
14769                    && comment_suffix_has_leading_space
14770                {
14771                    1
14772                } else {
14773                    0
14774                };
14775
14776                // If this line currently begins with the line comment prefix, then record
14777                // the range containing the prefix.
14778                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14779                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14780                    start..end
14781                } else {
14782                    end..end
14783                }
14784            }
14785
14786            // TODO: Handle selections that cross excerpts
14787            for selection in &mut selections {
14788                let start_column = snapshot
14789                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14790                    .len;
14791                let language = if let Some(language) =
14792                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14793                {
14794                    language
14795                } else {
14796                    continue;
14797                };
14798
14799                selection_edit_ranges.clear();
14800
14801                // If multiple selections contain a given row, avoid processing that
14802                // row more than once.
14803                let mut start_row = MultiBufferRow(selection.start.row);
14804                if last_toggled_row == Some(start_row) {
14805                    start_row = start_row.next_row();
14806                }
14807                let end_row =
14808                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14809                        MultiBufferRow(selection.end.row - 1)
14810                    } else {
14811                        MultiBufferRow(selection.end.row)
14812                    };
14813                last_toggled_row = Some(end_row);
14814
14815                if start_row > end_row {
14816                    continue;
14817                }
14818
14819                // If the language has line comments, toggle those.
14820                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14821
14822                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14823                if ignore_indent {
14824                    full_comment_prefixes = full_comment_prefixes
14825                        .into_iter()
14826                        .map(|s| Arc::from(s.trim_end()))
14827                        .collect();
14828                }
14829
14830                if !full_comment_prefixes.is_empty() {
14831                    let first_prefix = full_comment_prefixes
14832                        .first()
14833                        .expect("prefixes is non-empty");
14834                    let prefix_trimmed_lengths = full_comment_prefixes
14835                        .iter()
14836                        .map(|p| p.trim_end_matches(' ').len())
14837                        .collect::<SmallVec<[usize; 4]>>();
14838
14839                    let mut all_selection_lines_are_comments = true;
14840
14841                    for row in start_row.0..=end_row.0 {
14842                        let row = MultiBufferRow(row);
14843                        if start_row < end_row && snapshot.is_line_blank(row) {
14844                            continue;
14845                        }
14846
14847                        let prefix_range = full_comment_prefixes
14848                            .iter()
14849                            .zip(prefix_trimmed_lengths.iter().copied())
14850                            .map(|(prefix, trimmed_prefix_len)| {
14851                                comment_prefix_range(
14852                                    snapshot.deref(),
14853                                    row,
14854                                    &prefix[..trimmed_prefix_len],
14855                                    &prefix[trimmed_prefix_len..],
14856                                    ignore_indent,
14857                                )
14858                            })
14859                            .max_by_key(|range| range.end.column - range.start.column)
14860                            .expect("prefixes is non-empty");
14861
14862                        if prefix_range.is_empty() {
14863                            all_selection_lines_are_comments = false;
14864                        }
14865
14866                        selection_edit_ranges.push(prefix_range);
14867                    }
14868
14869                    if all_selection_lines_are_comments {
14870                        edits.extend(
14871                            selection_edit_ranges
14872                                .iter()
14873                                .cloned()
14874                                .map(|range| (range, empty_str.clone())),
14875                        );
14876                    } else {
14877                        let min_column = selection_edit_ranges
14878                            .iter()
14879                            .map(|range| range.start.column)
14880                            .min()
14881                            .unwrap_or(0);
14882                        edits.extend(selection_edit_ranges.iter().map(|range| {
14883                            let position = Point::new(range.start.row, min_column);
14884                            (position..position, first_prefix.clone())
14885                        }));
14886                    }
14887                } else if let Some(BlockCommentConfig {
14888                    start: full_comment_prefix,
14889                    end: comment_suffix,
14890                    ..
14891                }) = language.block_comment()
14892                {
14893                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14894                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14895                    let prefix_range = comment_prefix_range(
14896                        snapshot.deref(),
14897                        start_row,
14898                        comment_prefix,
14899                        comment_prefix_whitespace,
14900                        ignore_indent,
14901                    );
14902                    let suffix_range = comment_suffix_range(
14903                        snapshot.deref(),
14904                        end_row,
14905                        comment_suffix.trim_start_matches(' '),
14906                        comment_suffix.starts_with(' '),
14907                    );
14908
14909                    if prefix_range.is_empty() || suffix_range.is_empty() {
14910                        edits.push((
14911                            prefix_range.start..prefix_range.start,
14912                            full_comment_prefix.clone(),
14913                        ));
14914                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14915                        suffixes_inserted.push((end_row, comment_suffix.len()));
14916                    } else {
14917                        edits.push((prefix_range, empty_str.clone()));
14918                        edits.push((suffix_range, empty_str.clone()));
14919                    }
14920                } else {
14921                    continue;
14922                }
14923            }
14924
14925            drop(snapshot);
14926            this.buffer.update(cx, |buffer, cx| {
14927                buffer.edit(edits, None, cx);
14928            });
14929
14930            // Adjust selections so that they end before any comment suffixes that
14931            // were inserted.
14932            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14933            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
14934            let snapshot = this.buffer.read(cx).read(cx);
14935            for selection in &mut selections {
14936                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14937                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14938                        Ordering::Less => {
14939                            suffixes_inserted.next();
14940                            continue;
14941                        }
14942                        Ordering::Greater => break,
14943                        Ordering::Equal => {
14944                            if selection.end.column == snapshot.line_len(row) {
14945                                if selection.is_empty() {
14946                                    selection.start.column -= suffix_len as u32;
14947                                }
14948                                selection.end.column -= suffix_len as u32;
14949                            }
14950                            break;
14951                        }
14952                    }
14953                }
14954            }
14955
14956            drop(snapshot);
14957            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14958
14959            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
14960            let selections_on_single_row = selections.windows(2).all(|selections| {
14961                selections[0].start.row == selections[1].start.row
14962                    && selections[0].end.row == selections[1].end.row
14963                    && selections[0].start.row == selections[0].end.row
14964            });
14965            let selections_selecting = selections
14966                .iter()
14967                .any(|selection| selection.start != selection.end);
14968            let advance_downwards = action.advance_downwards
14969                && selections_on_single_row
14970                && !selections_selecting
14971                && !matches!(this.mode, EditorMode::SingleLine);
14972
14973            if advance_downwards {
14974                let snapshot = this.buffer.read(cx).snapshot(cx);
14975
14976                this.change_selections(Default::default(), window, cx, |s| {
14977                    s.move_cursors_with(|display_snapshot, display_point, _| {
14978                        let mut point = display_point.to_point(display_snapshot);
14979                        point.row += 1;
14980                        point = snapshot.clip_point(point, Bias::Left);
14981                        let display_point = point.to_display_point(display_snapshot);
14982                        let goal = SelectionGoal::HorizontalPosition(
14983                            display_snapshot
14984                                .x_for_display_point(display_point, text_layout_details)
14985                                .into(),
14986                        );
14987                        (display_point, goal)
14988                    })
14989                });
14990            }
14991        });
14992    }
14993
14994    pub fn select_enclosing_symbol(
14995        &mut self,
14996        _: &SelectEnclosingSymbol,
14997        window: &mut Window,
14998        cx: &mut Context<Self>,
14999    ) {
15000        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15001
15002        let buffer = self.buffer.read(cx).snapshot(cx);
15003        let old_selections = self
15004            .selections
15005            .all::<usize>(&self.display_snapshot(cx))
15006            .into_boxed_slice();
15007
15008        fn update_selection(
15009            selection: &Selection<usize>,
15010            buffer_snap: &MultiBufferSnapshot,
15011        ) -> Option<Selection<usize>> {
15012            let cursor = selection.head();
15013            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15014            for symbol in symbols.iter().rev() {
15015                let start = symbol.range.start.to_offset(buffer_snap);
15016                let end = symbol.range.end.to_offset(buffer_snap);
15017                let new_range = start..end;
15018                if start < selection.start || end > selection.end {
15019                    return Some(Selection {
15020                        id: selection.id,
15021                        start: new_range.start,
15022                        end: new_range.end,
15023                        goal: SelectionGoal::None,
15024                        reversed: selection.reversed,
15025                    });
15026                }
15027            }
15028            None
15029        }
15030
15031        let mut selected_larger_symbol = false;
15032        let new_selections = old_selections
15033            .iter()
15034            .map(|selection| match update_selection(selection, &buffer) {
15035                Some(new_selection) => {
15036                    if new_selection.range() != selection.range() {
15037                        selected_larger_symbol = true;
15038                    }
15039                    new_selection
15040                }
15041                None => selection.clone(),
15042            })
15043            .collect::<Vec<_>>();
15044
15045        if selected_larger_symbol {
15046            self.change_selections(Default::default(), window, cx, |s| {
15047                s.select(new_selections);
15048            });
15049        }
15050    }
15051
15052    pub fn select_larger_syntax_node(
15053        &mut self,
15054        _: &SelectLargerSyntaxNode,
15055        window: &mut Window,
15056        cx: &mut Context<Self>,
15057    ) {
15058        let Some(visible_row_count) = self.visible_row_count() else {
15059            return;
15060        };
15061        let old_selections: Box<[_]> = self
15062            .selections
15063            .all::<usize>(&self.display_snapshot(cx))
15064            .into();
15065        if old_selections.is_empty() {
15066            return;
15067        }
15068
15069        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15070
15071        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15072        let buffer = self.buffer.read(cx).snapshot(cx);
15073
15074        let mut selected_larger_node = false;
15075        let mut new_selections = old_selections
15076            .iter()
15077            .map(|selection| {
15078                let old_range = selection.start..selection.end;
15079
15080                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15081                    // manually select word at selection
15082                    if ["string_content", "inline"].contains(&node.kind()) {
15083                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15084                        // ignore if word is already selected
15085                        if !word_range.is_empty() && old_range != word_range {
15086                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15087                            // only select word if start and end point belongs to same word
15088                            if word_range == last_word_range {
15089                                selected_larger_node = true;
15090                                return Selection {
15091                                    id: selection.id,
15092                                    start: word_range.start,
15093                                    end: word_range.end,
15094                                    goal: SelectionGoal::None,
15095                                    reversed: selection.reversed,
15096                                };
15097                            }
15098                        }
15099                    }
15100                }
15101
15102                let mut new_range = old_range.clone();
15103                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15104                    new_range = range;
15105                    if !node.is_named() {
15106                        continue;
15107                    }
15108                    if !display_map.intersects_fold(new_range.start)
15109                        && !display_map.intersects_fold(new_range.end)
15110                    {
15111                        break;
15112                    }
15113                }
15114
15115                selected_larger_node |= new_range != old_range;
15116                Selection {
15117                    id: selection.id,
15118                    start: new_range.start,
15119                    end: new_range.end,
15120                    goal: SelectionGoal::None,
15121                    reversed: selection.reversed,
15122                }
15123            })
15124            .collect::<Vec<_>>();
15125
15126        if !selected_larger_node {
15127            return; // don't put this call in the history
15128        }
15129
15130        // scroll based on transformation done to the last selection created by the user
15131        let (last_old, last_new) = old_selections
15132            .last()
15133            .zip(new_selections.last().cloned())
15134            .expect("old_selections isn't empty");
15135
15136        // revert selection
15137        let is_selection_reversed = {
15138            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15139            new_selections.last_mut().expect("checked above").reversed =
15140                should_newest_selection_be_reversed;
15141            should_newest_selection_be_reversed
15142        };
15143
15144        if selected_larger_node {
15145            self.select_syntax_node_history.disable_clearing = true;
15146            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15147                s.select(new_selections.clone());
15148            });
15149            self.select_syntax_node_history.disable_clearing = false;
15150        }
15151
15152        let start_row = last_new.start.to_display_point(&display_map).row().0;
15153        let end_row = last_new.end.to_display_point(&display_map).row().0;
15154        let selection_height = end_row - start_row + 1;
15155        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15156
15157        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15158        let scroll_behavior = if fits_on_the_screen {
15159            self.request_autoscroll(Autoscroll::fit(), cx);
15160            SelectSyntaxNodeScrollBehavior::FitSelection
15161        } else if is_selection_reversed {
15162            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15163            SelectSyntaxNodeScrollBehavior::CursorTop
15164        } else {
15165            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15166            SelectSyntaxNodeScrollBehavior::CursorBottom
15167        };
15168
15169        self.select_syntax_node_history.push((
15170            old_selections,
15171            scroll_behavior,
15172            is_selection_reversed,
15173        ));
15174    }
15175
15176    pub fn select_smaller_syntax_node(
15177        &mut self,
15178        _: &SelectSmallerSyntaxNode,
15179        window: &mut Window,
15180        cx: &mut Context<Self>,
15181    ) {
15182        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15183
15184        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15185            self.select_syntax_node_history.pop()
15186        {
15187            if let Some(selection) = selections.last_mut() {
15188                selection.reversed = is_selection_reversed;
15189            }
15190
15191            self.select_syntax_node_history.disable_clearing = true;
15192            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15193                s.select(selections.to_vec());
15194            });
15195            self.select_syntax_node_history.disable_clearing = false;
15196
15197            match scroll_behavior {
15198                SelectSyntaxNodeScrollBehavior::CursorTop => {
15199                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15200                }
15201                SelectSyntaxNodeScrollBehavior::FitSelection => {
15202                    self.request_autoscroll(Autoscroll::fit(), cx);
15203                }
15204                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15205                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15206                }
15207            }
15208        }
15209    }
15210
15211    pub fn unwrap_syntax_node(
15212        &mut self,
15213        _: &UnwrapSyntaxNode,
15214        window: &mut Window,
15215        cx: &mut Context<Self>,
15216    ) {
15217        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15218
15219        let buffer = self.buffer.read(cx).snapshot(cx);
15220        let selections = self
15221            .selections
15222            .all::<usize>(&self.display_snapshot(cx))
15223            .into_iter()
15224            // subtracting the offset requires sorting
15225            .sorted_by_key(|i| i.start);
15226
15227        let full_edits = selections
15228            .into_iter()
15229            .filter_map(|selection| {
15230                let child = if selection.is_empty()
15231                    && let Some((_, ancestor_range)) =
15232                        buffer.syntax_ancestor(selection.start..selection.end)
15233                {
15234                    ancestor_range
15235                } else {
15236                    selection.range()
15237                };
15238
15239                let mut parent = child.clone();
15240                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15241                    parent = ancestor_range;
15242                    if parent.start < child.start || parent.end > child.end {
15243                        break;
15244                    }
15245                }
15246
15247                if parent == child {
15248                    return None;
15249                }
15250                let text = buffer.text_for_range(child).collect::<String>();
15251                Some((selection.id, parent, text))
15252            })
15253            .collect::<Vec<_>>();
15254        if full_edits.is_empty() {
15255            return;
15256        }
15257
15258        self.transact(window, cx, |this, window, cx| {
15259            this.buffer.update(cx, |buffer, cx| {
15260                buffer.edit(
15261                    full_edits
15262                        .iter()
15263                        .map(|(_, p, t)| (p.clone(), t.clone()))
15264                        .collect::<Vec<_>>(),
15265                    None,
15266                    cx,
15267                );
15268            });
15269            this.change_selections(Default::default(), window, cx, |s| {
15270                let mut offset = 0;
15271                let mut selections = vec![];
15272                for (id, parent, text) in full_edits {
15273                    let start = parent.start - offset;
15274                    offset += parent.len() - text.len();
15275                    selections.push(Selection {
15276                        id,
15277                        start,
15278                        end: start + text.len(),
15279                        reversed: false,
15280                        goal: Default::default(),
15281                    });
15282                }
15283                s.select(selections);
15284            });
15285        });
15286    }
15287
15288    pub fn select_next_syntax_node(
15289        &mut self,
15290        _: &SelectNextSyntaxNode,
15291        window: &mut Window,
15292        cx: &mut Context<Self>,
15293    ) {
15294        let old_selections: Box<[_]> = self
15295            .selections
15296            .all::<usize>(&self.display_snapshot(cx))
15297            .into();
15298        if old_selections.is_empty() {
15299            return;
15300        }
15301
15302        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15303
15304        let buffer = self.buffer.read(cx).snapshot(cx);
15305        let mut selected_sibling = false;
15306
15307        let new_selections = old_selections
15308            .iter()
15309            .map(|selection| {
15310                let old_range = selection.start..selection.end;
15311
15312                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15313                    let new_range = node.byte_range();
15314                    selected_sibling = true;
15315                    Selection {
15316                        id: selection.id,
15317                        start: new_range.start,
15318                        end: new_range.end,
15319                        goal: SelectionGoal::None,
15320                        reversed: selection.reversed,
15321                    }
15322                } else {
15323                    selection.clone()
15324                }
15325            })
15326            .collect::<Vec<_>>();
15327
15328        if selected_sibling {
15329            self.change_selections(
15330                SelectionEffects::scroll(Autoscroll::fit()),
15331                window,
15332                cx,
15333                |s| {
15334                    s.select(new_selections);
15335                },
15336            );
15337        }
15338    }
15339
15340    pub fn select_prev_syntax_node(
15341        &mut self,
15342        _: &SelectPreviousSyntaxNode,
15343        window: &mut Window,
15344        cx: &mut Context<Self>,
15345    ) {
15346        let old_selections: Box<[_]> = self
15347            .selections
15348            .all::<usize>(&self.display_snapshot(cx))
15349            .into();
15350        if old_selections.is_empty() {
15351            return;
15352        }
15353
15354        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15355
15356        let buffer = self.buffer.read(cx).snapshot(cx);
15357        let mut selected_sibling = false;
15358
15359        let new_selections = old_selections
15360            .iter()
15361            .map(|selection| {
15362                let old_range = selection.start..selection.end;
15363
15364                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15365                    let new_range = node.byte_range();
15366                    selected_sibling = true;
15367                    Selection {
15368                        id: selection.id,
15369                        start: new_range.start,
15370                        end: new_range.end,
15371                        goal: SelectionGoal::None,
15372                        reversed: selection.reversed,
15373                    }
15374                } else {
15375                    selection.clone()
15376                }
15377            })
15378            .collect::<Vec<_>>();
15379
15380        if selected_sibling {
15381            self.change_selections(
15382                SelectionEffects::scroll(Autoscroll::fit()),
15383                window,
15384                cx,
15385                |s| {
15386                    s.select(new_selections);
15387                },
15388            );
15389        }
15390    }
15391
15392    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15393        if !EditorSettings::get_global(cx).gutter.runnables {
15394            self.clear_tasks();
15395            return Task::ready(());
15396        }
15397        let project = self.project().map(Entity::downgrade);
15398        let task_sources = self.lsp_task_sources(cx);
15399        let multi_buffer = self.buffer.downgrade();
15400        cx.spawn_in(window, async move |editor, cx| {
15401            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15402            let Some(project) = project.and_then(|p| p.upgrade()) else {
15403                return;
15404            };
15405            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15406                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15407            }) else {
15408                return;
15409            };
15410
15411            let hide_runnables = project
15412                .update(cx, |project, _| project.is_via_collab())
15413                .unwrap_or(true);
15414            if hide_runnables {
15415                return;
15416            }
15417            let new_rows =
15418                cx.background_spawn({
15419                    let snapshot = display_snapshot.clone();
15420                    async move {
15421                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15422                    }
15423                })
15424                    .await;
15425            let Ok(lsp_tasks) =
15426                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15427            else {
15428                return;
15429            };
15430            let lsp_tasks = lsp_tasks.await;
15431
15432            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15433                lsp_tasks
15434                    .into_iter()
15435                    .flat_map(|(kind, tasks)| {
15436                        tasks.into_iter().filter_map(move |(location, task)| {
15437                            Some((kind.clone(), location?, task))
15438                        })
15439                    })
15440                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15441                        let buffer = location.target.buffer;
15442                        let buffer_snapshot = buffer.read(cx).snapshot();
15443                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15444                            |(excerpt_id, snapshot, _)| {
15445                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15446                                    display_snapshot
15447                                        .buffer_snapshot()
15448                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15449                                } else {
15450                                    None
15451                                }
15452                            },
15453                        );
15454                        if let Some(offset) = offset {
15455                            let task_buffer_range =
15456                                location.target.range.to_point(&buffer_snapshot);
15457                            let context_buffer_range =
15458                                task_buffer_range.to_offset(&buffer_snapshot);
15459                            let context_range = BufferOffset(context_buffer_range.start)
15460                                ..BufferOffset(context_buffer_range.end);
15461
15462                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15463                                .or_insert_with(|| RunnableTasks {
15464                                    templates: Vec::new(),
15465                                    offset,
15466                                    column: task_buffer_range.start.column,
15467                                    extra_variables: HashMap::default(),
15468                                    context_range,
15469                                })
15470                                .templates
15471                                .push((kind, task.original_task().clone()));
15472                        }
15473
15474                        acc
15475                    })
15476            }) else {
15477                return;
15478            };
15479
15480            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15481                buffer.language_settings(cx).tasks.prefer_lsp
15482            }) else {
15483                return;
15484            };
15485
15486            let rows = Self::runnable_rows(
15487                project,
15488                display_snapshot,
15489                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15490                new_rows,
15491                cx.clone(),
15492            )
15493            .await;
15494            editor
15495                .update(cx, |editor, _| {
15496                    editor.clear_tasks();
15497                    for (key, mut value) in rows {
15498                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15499                            value.templates.extend(lsp_tasks.templates);
15500                        }
15501
15502                        editor.insert_tasks(key, value);
15503                    }
15504                    for (key, value) in lsp_tasks_by_rows {
15505                        editor.insert_tasks(key, value);
15506                    }
15507                })
15508                .ok();
15509        })
15510    }
15511    fn fetch_runnable_ranges(
15512        snapshot: &DisplaySnapshot,
15513        range: Range<Anchor>,
15514    ) -> Vec<language::RunnableRange> {
15515        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15516    }
15517
15518    fn runnable_rows(
15519        project: Entity<Project>,
15520        snapshot: DisplaySnapshot,
15521        prefer_lsp: bool,
15522        runnable_ranges: Vec<RunnableRange>,
15523        cx: AsyncWindowContext,
15524    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15525        cx.spawn(async move |cx| {
15526            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15527            for mut runnable in runnable_ranges {
15528                let Some(tasks) = cx
15529                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15530                    .ok()
15531                else {
15532                    continue;
15533                };
15534                let mut tasks = tasks.await;
15535
15536                if prefer_lsp {
15537                    tasks.retain(|(task_kind, _)| {
15538                        !matches!(task_kind, TaskSourceKind::Language { .. })
15539                    });
15540                }
15541                if tasks.is_empty() {
15542                    continue;
15543                }
15544
15545                let point = runnable
15546                    .run_range
15547                    .start
15548                    .to_point(&snapshot.buffer_snapshot());
15549                let Some(row) = snapshot
15550                    .buffer_snapshot()
15551                    .buffer_line_for_row(MultiBufferRow(point.row))
15552                    .map(|(_, range)| range.start.row)
15553                else {
15554                    continue;
15555                };
15556
15557                let context_range =
15558                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15559                runnable_rows.push((
15560                    (runnable.buffer_id, row),
15561                    RunnableTasks {
15562                        templates: tasks,
15563                        offset: snapshot
15564                            .buffer_snapshot()
15565                            .anchor_before(runnable.run_range.start),
15566                        context_range,
15567                        column: point.column,
15568                        extra_variables: runnable.extra_captures,
15569                    },
15570                ));
15571            }
15572            runnable_rows
15573        })
15574    }
15575
15576    fn templates_with_tags(
15577        project: &Entity<Project>,
15578        runnable: &mut Runnable,
15579        cx: &mut App,
15580    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15581        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15582            let (worktree_id, file) = project
15583                .buffer_for_id(runnable.buffer, cx)
15584                .and_then(|buffer| buffer.read(cx).file())
15585                .map(|file| (file.worktree_id(cx), file.clone()))
15586                .unzip();
15587
15588            (
15589                project.task_store().read(cx).task_inventory().cloned(),
15590                worktree_id,
15591                file,
15592            )
15593        });
15594
15595        let tags = mem::take(&mut runnable.tags);
15596        let language = runnable.language.clone();
15597        cx.spawn(async move |cx| {
15598            let mut templates_with_tags = Vec::new();
15599            if let Some(inventory) = inventory {
15600                for RunnableTag(tag) in tags {
15601                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15602                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15603                    }) else {
15604                        return templates_with_tags;
15605                    };
15606                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15607                        move |(_, template)| {
15608                            template.tags.iter().any(|source_tag| source_tag == &tag)
15609                        },
15610                    ));
15611                }
15612            }
15613            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15614
15615            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15616                // Strongest source wins; if we have worktree tag binding, prefer that to
15617                // global and language bindings;
15618                // if we have a global binding, prefer that to language binding.
15619                let first_mismatch = templates_with_tags
15620                    .iter()
15621                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15622                if let Some(index) = first_mismatch {
15623                    templates_with_tags.truncate(index);
15624                }
15625            }
15626
15627            templates_with_tags
15628        })
15629    }
15630
15631    pub fn move_to_enclosing_bracket(
15632        &mut self,
15633        _: &MoveToEnclosingBracket,
15634        window: &mut Window,
15635        cx: &mut Context<Self>,
15636    ) {
15637        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15638        self.change_selections(Default::default(), window, cx, |s| {
15639            s.move_offsets_with(|snapshot, selection| {
15640                let Some(enclosing_bracket_ranges) =
15641                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15642                else {
15643                    return;
15644                };
15645
15646                let mut best_length = usize::MAX;
15647                let mut best_inside = false;
15648                let mut best_in_bracket_range = false;
15649                let mut best_destination = None;
15650                for (open, close) in enclosing_bracket_ranges {
15651                    let close = close.to_inclusive();
15652                    let length = close.end() - open.start;
15653                    let inside = selection.start >= open.end && selection.end <= *close.start();
15654                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15655                        || close.contains(&selection.head());
15656
15657                    // If best is next to a bracket and current isn't, skip
15658                    if !in_bracket_range && best_in_bracket_range {
15659                        continue;
15660                    }
15661
15662                    // Prefer smaller lengths unless best is inside and current isn't
15663                    if length > best_length && (best_inside || !inside) {
15664                        continue;
15665                    }
15666
15667                    best_length = length;
15668                    best_inside = inside;
15669                    best_in_bracket_range = in_bracket_range;
15670                    best_destination = Some(
15671                        if close.contains(&selection.start) && close.contains(&selection.end) {
15672                            if inside { open.end } else { open.start }
15673                        } else if inside {
15674                            *close.start()
15675                        } else {
15676                            *close.end()
15677                        },
15678                    );
15679                }
15680
15681                if let Some(destination) = best_destination {
15682                    selection.collapse_to(destination, SelectionGoal::None);
15683                }
15684            })
15685        });
15686    }
15687
15688    pub fn undo_selection(
15689        &mut self,
15690        _: &UndoSelection,
15691        window: &mut Window,
15692        cx: &mut Context<Self>,
15693    ) {
15694        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15695        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15696            self.selection_history.mode = SelectionHistoryMode::Undoing;
15697            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15698                this.end_selection(window, cx);
15699                this.change_selections(
15700                    SelectionEffects::scroll(Autoscroll::newest()),
15701                    window,
15702                    cx,
15703                    |s| s.select_anchors(entry.selections.to_vec()),
15704                );
15705            });
15706            self.selection_history.mode = SelectionHistoryMode::Normal;
15707
15708            self.select_next_state = entry.select_next_state;
15709            self.select_prev_state = entry.select_prev_state;
15710            self.add_selections_state = entry.add_selections_state;
15711        }
15712    }
15713
15714    pub fn redo_selection(
15715        &mut self,
15716        _: &RedoSelection,
15717        window: &mut Window,
15718        cx: &mut Context<Self>,
15719    ) {
15720        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15721        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15722            self.selection_history.mode = SelectionHistoryMode::Redoing;
15723            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15724                this.end_selection(window, cx);
15725                this.change_selections(
15726                    SelectionEffects::scroll(Autoscroll::newest()),
15727                    window,
15728                    cx,
15729                    |s| s.select_anchors(entry.selections.to_vec()),
15730                );
15731            });
15732            self.selection_history.mode = SelectionHistoryMode::Normal;
15733
15734            self.select_next_state = entry.select_next_state;
15735            self.select_prev_state = entry.select_prev_state;
15736            self.add_selections_state = entry.add_selections_state;
15737        }
15738    }
15739
15740    pub fn expand_excerpts(
15741        &mut self,
15742        action: &ExpandExcerpts,
15743        _: &mut Window,
15744        cx: &mut Context<Self>,
15745    ) {
15746        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15747    }
15748
15749    pub fn expand_excerpts_down(
15750        &mut self,
15751        action: &ExpandExcerptsDown,
15752        _: &mut Window,
15753        cx: &mut Context<Self>,
15754    ) {
15755        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15756    }
15757
15758    pub fn expand_excerpts_up(
15759        &mut self,
15760        action: &ExpandExcerptsUp,
15761        _: &mut Window,
15762        cx: &mut Context<Self>,
15763    ) {
15764        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15765    }
15766
15767    pub fn expand_excerpts_for_direction(
15768        &mut self,
15769        lines: u32,
15770        direction: ExpandExcerptDirection,
15771
15772        cx: &mut Context<Self>,
15773    ) {
15774        let selections = self.selections.disjoint_anchors_arc();
15775
15776        let lines = if lines == 0 {
15777            EditorSettings::get_global(cx).expand_excerpt_lines
15778        } else {
15779            lines
15780        };
15781
15782        self.buffer.update(cx, |buffer, cx| {
15783            let snapshot = buffer.snapshot(cx);
15784            let mut excerpt_ids = selections
15785                .iter()
15786                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15787                .collect::<Vec<_>>();
15788            excerpt_ids.sort();
15789            excerpt_ids.dedup();
15790            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15791        })
15792    }
15793
15794    pub fn expand_excerpt(
15795        &mut self,
15796        excerpt: ExcerptId,
15797        direction: ExpandExcerptDirection,
15798        window: &mut Window,
15799        cx: &mut Context<Self>,
15800    ) {
15801        let current_scroll_position = self.scroll_position(cx);
15802        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15803        let mut should_scroll_up = false;
15804
15805        if direction == ExpandExcerptDirection::Down {
15806            let multi_buffer = self.buffer.read(cx);
15807            let snapshot = multi_buffer.snapshot(cx);
15808            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15809                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15810                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15811            {
15812                let buffer_snapshot = buffer.read(cx).snapshot();
15813                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15814                let last_row = buffer_snapshot.max_point().row;
15815                let lines_below = last_row.saturating_sub(excerpt_end_row);
15816                should_scroll_up = lines_below >= lines_to_expand;
15817            }
15818        }
15819
15820        self.buffer.update(cx, |buffer, cx| {
15821            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15822        });
15823
15824        if should_scroll_up {
15825            let new_scroll_position =
15826                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
15827            self.set_scroll_position(new_scroll_position, window, cx);
15828        }
15829    }
15830
15831    pub fn go_to_singleton_buffer_point(
15832        &mut self,
15833        point: Point,
15834        window: &mut Window,
15835        cx: &mut Context<Self>,
15836    ) {
15837        self.go_to_singleton_buffer_range(point..point, window, cx);
15838    }
15839
15840    pub fn go_to_singleton_buffer_range(
15841        &mut self,
15842        range: Range<Point>,
15843        window: &mut Window,
15844        cx: &mut Context<Self>,
15845    ) {
15846        let multibuffer = self.buffer().read(cx);
15847        let Some(buffer) = multibuffer.as_singleton() else {
15848            return;
15849        };
15850        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15851            return;
15852        };
15853        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15854            return;
15855        };
15856        self.change_selections(
15857            SelectionEffects::default().nav_history(true),
15858            window,
15859            cx,
15860            |s| s.select_anchor_ranges([start..end]),
15861        );
15862    }
15863
15864    pub fn go_to_diagnostic(
15865        &mut self,
15866        action: &GoToDiagnostic,
15867        window: &mut Window,
15868        cx: &mut Context<Self>,
15869    ) {
15870        if !self.diagnostics_enabled() {
15871            return;
15872        }
15873        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15874        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15875    }
15876
15877    pub fn go_to_prev_diagnostic(
15878        &mut self,
15879        action: &GoToPreviousDiagnostic,
15880        window: &mut Window,
15881        cx: &mut Context<Self>,
15882    ) {
15883        if !self.diagnostics_enabled() {
15884            return;
15885        }
15886        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15887        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15888    }
15889
15890    pub fn go_to_diagnostic_impl(
15891        &mut self,
15892        direction: Direction,
15893        severity: GoToDiagnosticSeverityFilter,
15894        window: &mut Window,
15895        cx: &mut Context<Self>,
15896    ) {
15897        let buffer = self.buffer.read(cx).snapshot(cx);
15898        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
15899
15900        let mut active_group_id = None;
15901        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15902            && active_group.active_range.start.to_offset(&buffer) == selection.start
15903        {
15904            active_group_id = Some(active_group.group_id);
15905        }
15906
15907        fn filtered<'a>(
15908            snapshot: EditorSnapshot,
15909            severity: GoToDiagnosticSeverityFilter,
15910            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
15911        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
15912            diagnostics
15913                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15914                .filter(|entry| entry.range.start != entry.range.end)
15915                .filter(|entry| !entry.diagnostic.is_unnecessary)
15916                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15917        }
15918
15919        let snapshot = self.snapshot(window, cx);
15920        let before = filtered(
15921            snapshot.clone(),
15922            severity,
15923            buffer
15924                .diagnostics_in_range(0..selection.start)
15925                .filter(|entry| entry.range.start <= selection.start),
15926        );
15927        let after = filtered(
15928            snapshot,
15929            severity,
15930            buffer
15931                .diagnostics_in_range(selection.start..buffer.len())
15932                .filter(|entry| entry.range.start >= selection.start),
15933        );
15934
15935        let mut found: Option<DiagnosticEntryRef<usize>> = None;
15936        if direction == Direction::Prev {
15937            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15938            {
15939                for diagnostic in prev_diagnostics.into_iter().rev() {
15940                    if diagnostic.range.start != selection.start
15941                        || active_group_id
15942                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15943                    {
15944                        found = Some(diagnostic);
15945                        break 'outer;
15946                    }
15947                }
15948            }
15949        } else {
15950            for diagnostic in after.chain(before) {
15951                if diagnostic.range.start != selection.start
15952                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15953                {
15954                    found = Some(diagnostic);
15955                    break;
15956                }
15957            }
15958        }
15959        let Some(next_diagnostic) = found else {
15960            return;
15961        };
15962
15963        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15964        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15965            return;
15966        };
15967        self.change_selections(Default::default(), window, cx, |s| {
15968            s.select_ranges(vec![
15969                next_diagnostic.range.start..next_diagnostic.range.start,
15970            ])
15971        });
15972        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15973        self.refresh_edit_prediction(false, true, window, cx);
15974    }
15975
15976    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15977        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15978        let snapshot = self.snapshot(window, cx);
15979        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
15980        self.go_to_hunk_before_or_after_position(
15981            &snapshot,
15982            selection.head(),
15983            Direction::Next,
15984            window,
15985            cx,
15986        );
15987    }
15988
15989    pub fn go_to_hunk_before_or_after_position(
15990        &mut self,
15991        snapshot: &EditorSnapshot,
15992        position: Point,
15993        direction: Direction,
15994        window: &mut Window,
15995        cx: &mut Context<Editor>,
15996    ) {
15997        let row = if direction == Direction::Next {
15998            self.hunk_after_position(snapshot, position)
15999                .map(|hunk| hunk.row_range.start)
16000        } else {
16001            self.hunk_before_position(snapshot, position)
16002        };
16003
16004        if let Some(row) = row {
16005            let destination = Point::new(row.0, 0);
16006            let autoscroll = Autoscroll::center();
16007
16008            self.unfold_ranges(&[destination..destination], false, false, cx);
16009            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16010                s.select_ranges([destination..destination]);
16011            });
16012        }
16013    }
16014
16015    fn hunk_after_position(
16016        &mut self,
16017        snapshot: &EditorSnapshot,
16018        position: Point,
16019    ) -> Option<MultiBufferDiffHunk> {
16020        snapshot
16021            .buffer_snapshot()
16022            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16023            .find(|hunk| hunk.row_range.start.0 > position.row)
16024            .or_else(|| {
16025                snapshot
16026                    .buffer_snapshot()
16027                    .diff_hunks_in_range(Point::zero()..position)
16028                    .find(|hunk| hunk.row_range.end.0 < position.row)
16029            })
16030    }
16031
16032    fn go_to_prev_hunk(
16033        &mut self,
16034        _: &GoToPreviousHunk,
16035        window: &mut Window,
16036        cx: &mut Context<Self>,
16037    ) {
16038        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16039        let snapshot = self.snapshot(window, cx);
16040        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16041        self.go_to_hunk_before_or_after_position(
16042            &snapshot,
16043            selection.head(),
16044            Direction::Prev,
16045            window,
16046            cx,
16047        );
16048    }
16049
16050    fn hunk_before_position(
16051        &mut self,
16052        snapshot: &EditorSnapshot,
16053        position: Point,
16054    ) -> Option<MultiBufferRow> {
16055        snapshot
16056            .buffer_snapshot()
16057            .diff_hunk_before(position)
16058            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16059    }
16060
16061    fn go_to_next_change(
16062        &mut self,
16063        _: &GoToNextChange,
16064        window: &mut Window,
16065        cx: &mut Context<Self>,
16066    ) {
16067        if let Some(selections) = self
16068            .change_list
16069            .next_change(1, Direction::Next)
16070            .map(|s| s.to_vec())
16071        {
16072            self.change_selections(Default::default(), window, cx, |s| {
16073                let map = s.display_map();
16074                s.select_display_ranges(selections.iter().map(|a| {
16075                    let point = a.to_display_point(&map);
16076                    point..point
16077                }))
16078            })
16079        }
16080    }
16081
16082    fn go_to_previous_change(
16083        &mut self,
16084        _: &GoToPreviousChange,
16085        window: &mut Window,
16086        cx: &mut Context<Self>,
16087    ) {
16088        if let Some(selections) = self
16089            .change_list
16090            .next_change(1, Direction::Prev)
16091            .map(|s| s.to_vec())
16092        {
16093            self.change_selections(Default::default(), window, cx, |s| {
16094                let map = s.display_map();
16095                s.select_display_ranges(selections.iter().map(|a| {
16096                    let point = a.to_display_point(&map);
16097                    point..point
16098                }))
16099            })
16100        }
16101    }
16102
16103    pub fn go_to_next_document_highlight(
16104        &mut self,
16105        _: &GoToNextDocumentHighlight,
16106        window: &mut Window,
16107        cx: &mut Context<Self>,
16108    ) {
16109        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16110    }
16111
16112    pub fn go_to_prev_document_highlight(
16113        &mut self,
16114        _: &GoToPreviousDocumentHighlight,
16115        window: &mut Window,
16116        cx: &mut Context<Self>,
16117    ) {
16118        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16119    }
16120
16121    pub fn go_to_document_highlight_before_or_after_position(
16122        &mut self,
16123        direction: Direction,
16124        window: &mut Window,
16125        cx: &mut Context<Editor>,
16126    ) {
16127        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16128        let snapshot = self.snapshot(window, cx);
16129        let buffer = &snapshot.buffer_snapshot();
16130        let position = self
16131            .selections
16132            .newest::<Point>(&snapshot.display_snapshot)
16133            .head();
16134        let anchor_position = buffer.anchor_after(position);
16135
16136        // Get all document highlights (both read and write)
16137        let mut all_highlights = Vec::new();
16138
16139        if let Some((_, read_highlights)) = self
16140            .background_highlights
16141            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16142        {
16143            all_highlights.extend(read_highlights.iter());
16144        }
16145
16146        if let Some((_, write_highlights)) = self
16147            .background_highlights
16148            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16149        {
16150            all_highlights.extend(write_highlights.iter());
16151        }
16152
16153        if all_highlights.is_empty() {
16154            return;
16155        }
16156
16157        // Sort highlights by position
16158        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16159
16160        let target_highlight = match direction {
16161            Direction::Next => {
16162                // Find the first highlight after the current position
16163                all_highlights
16164                    .iter()
16165                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16166            }
16167            Direction::Prev => {
16168                // Find the last highlight before the current position
16169                all_highlights
16170                    .iter()
16171                    .rev()
16172                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16173            }
16174        };
16175
16176        if let Some(highlight) = target_highlight {
16177            let destination = highlight.start.to_point(buffer);
16178            let autoscroll = Autoscroll::center();
16179
16180            self.unfold_ranges(&[destination..destination], false, false, cx);
16181            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16182                s.select_ranges([destination..destination]);
16183            });
16184        }
16185    }
16186
16187    fn go_to_line<T: 'static>(
16188        &mut self,
16189        position: Anchor,
16190        highlight_color: Option<Hsla>,
16191        window: &mut Window,
16192        cx: &mut Context<Self>,
16193    ) {
16194        let snapshot = self.snapshot(window, cx).display_snapshot;
16195        let position = position.to_point(&snapshot.buffer_snapshot());
16196        let start = snapshot
16197            .buffer_snapshot()
16198            .clip_point(Point::new(position.row, 0), Bias::Left);
16199        let end = start + Point::new(1, 0);
16200        let start = snapshot.buffer_snapshot().anchor_before(start);
16201        let end = snapshot.buffer_snapshot().anchor_before(end);
16202
16203        self.highlight_rows::<T>(
16204            start..end,
16205            highlight_color
16206                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16207            Default::default(),
16208            cx,
16209        );
16210
16211        if self.buffer.read(cx).is_singleton() {
16212            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16213        }
16214    }
16215
16216    pub fn go_to_definition(
16217        &mut self,
16218        _: &GoToDefinition,
16219        window: &mut Window,
16220        cx: &mut Context<Self>,
16221    ) -> Task<Result<Navigated>> {
16222        let definition =
16223            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16224        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16225        cx.spawn_in(window, async move |editor, cx| {
16226            if definition.await? == Navigated::Yes {
16227                return Ok(Navigated::Yes);
16228            }
16229            match fallback_strategy {
16230                GoToDefinitionFallback::None => Ok(Navigated::No),
16231                GoToDefinitionFallback::FindAllReferences => {
16232                    match editor.update_in(cx, |editor, window, cx| {
16233                        editor.find_all_references(&FindAllReferences, window, cx)
16234                    })? {
16235                        Some(references) => references.await,
16236                        None => Ok(Navigated::No),
16237                    }
16238                }
16239            }
16240        })
16241    }
16242
16243    pub fn go_to_declaration(
16244        &mut self,
16245        _: &GoToDeclaration,
16246        window: &mut Window,
16247        cx: &mut Context<Self>,
16248    ) -> Task<Result<Navigated>> {
16249        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16250    }
16251
16252    pub fn go_to_declaration_split(
16253        &mut self,
16254        _: &GoToDeclaration,
16255        window: &mut Window,
16256        cx: &mut Context<Self>,
16257    ) -> Task<Result<Navigated>> {
16258        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16259    }
16260
16261    pub fn go_to_implementation(
16262        &mut self,
16263        _: &GoToImplementation,
16264        window: &mut Window,
16265        cx: &mut Context<Self>,
16266    ) -> Task<Result<Navigated>> {
16267        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16268    }
16269
16270    pub fn go_to_implementation_split(
16271        &mut self,
16272        _: &GoToImplementationSplit,
16273        window: &mut Window,
16274        cx: &mut Context<Self>,
16275    ) -> Task<Result<Navigated>> {
16276        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16277    }
16278
16279    pub fn go_to_type_definition(
16280        &mut self,
16281        _: &GoToTypeDefinition,
16282        window: &mut Window,
16283        cx: &mut Context<Self>,
16284    ) -> Task<Result<Navigated>> {
16285        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16286    }
16287
16288    pub fn go_to_definition_split(
16289        &mut self,
16290        _: &GoToDefinitionSplit,
16291        window: &mut Window,
16292        cx: &mut Context<Self>,
16293    ) -> Task<Result<Navigated>> {
16294        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16295    }
16296
16297    pub fn go_to_type_definition_split(
16298        &mut self,
16299        _: &GoToTypeDefinitionSplit,
16300        window: &mut Window,
16301        cx: &mut Context<Self>,
16302    ) -> Task<Result<Navigated>> {
16303        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16304    }
16305
16306    fn go_to_definition_of_kind(
16307        &mut self,
16308        kind: GotoDefinitionKind,
16309        split: bool,
16310        window: &mut Window,
16311        cx: &mut Context<Self>,
16312    ) -> Task<Result<Navigated>> {
16313        let Some(provider) = self.semantics_provider.clone() else {
16314            return Task::ready(Ok(Navigated::No));
16315        };
16316        let head = self
16317            .selections
16318            .newest::<usize>(&self.display_snapshot(cx))
16319            .head();
16320        let buffer = self.buffer.read(cx);
16321        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16322            return Task::ready(Ok(Navigated::No));
16323        };
16324        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16325            return Task::ready(Ok(Navigated::No));
16326        };
16327
16328        cx.spawn_in(window, async move |editor, cx| {
16329            let Some(definitions) = definitions.await? else {
16330                return Ok(Navigated::No);
16331            };
16332            let navigated = editor
16333                .update_in(cx, |editor, window, cx| {
16334                    editor.navigate_to_hover_links(
16335                        Some(kind),
16336                        definitions
16337                            .into_iter()
16338                            .filter(|location| {
16339                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16340                            })
16341                            .map(HoverLink::Text)
16342                            .collect::<Vec<_>>(),
16343                        split,
16344                        window,
16345                        cx,
16346                    )
16347                })?
16348                .await?;
16349            anyhow::Ok(navigated)
16350        })
16351    }
16352
16353    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16354        let selection = self.selections.newest_anchor();
16355        let head = selection.head();
16356        let tail = selection.tail();
16357
16358        let Some((buffer, start_position)) =
16359            self.buffer.read(cx).text_anchor_for_position(head, cx)
16360        else {
16361            return;
16362        };
16363
16364        let end_position = if head != tail {
16365            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16366                return;
16367            };
16368            Some(pos)
16369        } else {
16370            None
16371        };
16372
16373        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16374            let url = if let Some(end_pos) = end_position {
16375                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16376            } else {
16377                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16378            };
16379
16380            if let Some(url) = url {
16381                cx.update(|window, cx| {
16382                    if parse_zed_link(&url, cx).is_some() {
16383                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16384                    } else {
16385                        cx.open_url(&url);
16386                    }
16387                })?;
16388            }
16389
16390            anyhow::Ok(())
16391        });
16392
16393        url_finder.detach();
16394    }
16395
16396    pub fn open_selected_filename(
16397        &mut self,
16398        _: &OpenSelectedFilename,
16399        window: &mut Window,
16400        cx: &mut Context<Self>,
16401    ) {
16402        let Some(workspace) = self.workspace() else {
16403            return;
16404        };
16405
16406        let position = self.selections.newest_anchor().head();
16407
16408        let Some((buffer, buffer_position)) =
16409            self.buffer.read(cx).text_anchor_for_position(position, cx)
16410        else {
16411            return;
16412        };
16413
16414        let project = self.project.clone();
16415
16416        cx.spawn_in(window, async move |_, cx| {
16417            let result = find_file(&buffer, project, buffer_position, cx).await;
16418
16419            if let Some((_, path)) = result {
16420                workspace
16421                    .update_in(cx, |workspace, window, cx| {
16422                        workspace.open_resolved_path(path, window, cx)
16423                    })?
16424                    .await?;
16425            }
16426            anyhow::Ok(())
16427        })
16428        .detach();
16429    }
16430
16431    pub(crate) fn navigate_to_hover_links(
16432        &mut self,
16433        kind: Option<GotoDefinitionKind>,
16434        definitions: Vec<HoverLink>,
16435        split: bool,
16436        window: &mut Window,
16437        cx: &mut Context<Editor>,
16438    ) -> Task<Result<Navigated>> {
16439        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16440        let mut first_url_or_file = None;
16441        let definitions: Vec<_> = definitions
16442            .into_iter()
16443            .filter_map(|def| match def {
16444                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16445                HoverLink::InlayHint(lsp_location, server_id) => {
16446                    let computation =
16447                        self.compute_target_location(lsp_location, server_id, window, cx);
16448                    Some(cx.background_spawn(computation))
16449                }
16450                HoverLink::Url(url) => {
16451                    first_url_or_file = Some(Either::Left(url));
16452                    None
16453                }
16454                HoverLink::File(path) => {
16455                    first_url_or_file = Some(Either::Right(path));
16456                    None
16457                }
16458            })
16459            .collect();
16460
16461        let workspace = self.workspace();
16462
16463        cx.spawn_in(window, async move |editor, cx| {
16464            let locations: Vec<Location> = future::join_all(definitions)
16465                .await
16466                .into_iter()
16467                .filter_map(|location| location.transpose())
16468                .collect::<Result<_>>()
16469                .context("location tasks")?;
16470            let mut locations = cx.update(|_, cx| {
16471                locations
16472                    .into_iter()
16473                    .map(|location| {
16474                        let buffer = location.buffer.read(cx);
16475                        (location.buffer, location.range.to_point(buffer))
16476                    })
16477                    .into_group_map()
16478            })?;
16479            let mut num_locations = 0;
16480            for ranges in locations.values_mut() {
16481                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16482                ranges.dedup();
16483                num_locations += ranges.len();
16484            }
16485
16486            if num_locations > 1 {
16487                let Some(workspace) = workspace else {
16488                    return Ok(Navigated::No);
16489                };
16490
16491                let tab_kind = match kind {
16492                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16493                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16494                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16495                    Some(GotoDefinitionKind::Type) => "Types",
16496                };
16497                let title = editor
16498                    .update_in(cx, |_, _, cx| {
16499                        let target = locations
16500                            .iter()
16501                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16502                            .map(|(buffer, location)| {
16503                                buffer
16504                                    .read(cx)
16505                                    .text_for_range(location.clone())
16506                                    .collect::<String>()
16507                            })
16508                            .filter(|text| !text.contains('\n'))
16509                            .unique()
16510                            .take(3)
16511                            .join(", ");
16512                        if target.is_empty() {
16513                            tab_kind.to_owned()
16514                        } else {
16515                            format!("{tab_kind} for {target}")
16516                        }
16517                    })
16518                    .context("buffer title")?;
16519
16520                let opened = workspace
16521                    .update_in(cx, |workspace, window, cx| {
16522                        Self::open_locations_in_multibuffer(
16523                            workspace,
16524                            locations,
16525                            title,
16526                            split,
16527                            MultibufferSelectionMode::First,
16528                            window,
16529                            cx,
16530                        )
16531                    })
16532                    .is_ok();
16533
16534                anyhow::Ok(Navigated::from_bool(opened))
16535            } else if num_locations == 0 {
16536                // If there is one url or file, open it directly
16537                match first_url_or_file {
16538                    Some(Either::Left(url)) => {
16539                        cx.update(|_, cx| cx.open_url(&url))?;
16540                        Ok(Navigated::Yes)
16541                    }
16542                    Some(Either::Right(path)) => {
16543                        let Some(workspace) = workspace else {
16544                            return Ok(Navigated::No);
16545                        };
16546
16547                        workspace
16548                            .update_in(cx, |workspace, window, cx| {
16549                                workspace.open_resolved_path(path, window, cx)
16550                            })?
16551                            .await?;
16552                        Ok(Navigated::Yes)
16553                    }
16554                    None => Ok(Navigated::No),
16555                }
16556            } else {
16557                let Some(workspace) = workspace else {
16558                    return Ok(Navigated::No);
16559                };
16560
16561                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16562                let target_range = target_ranges.first().unwrap().clone();
16563
16564                editor.update_in(cx, |editor, window, cx| {
16565                    let range = target_range.to_point(target_buffer.read(cx));
16566                    let range = editor.range_for_match(&range);
16567                    let range = collapse_multiline_range(range);
16568
16569                    if !split
16570                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16571                    {
16572                        editor.go_to_singleton_buffer_range(range, window, cx);
16573                    } else {
16574                        let pane = workspace.read(cx).active_pane().clone();
16575                        window.defer(cx, move |window, cx| {
16576                            let target_editor: Entity<Self> =
16577                                workspace.update(cx, |workspace, cx| {
16578                                    let pane = if split {
16579                                        workspace.adjacent_pane(window, cx)
16580                                    } else {
16581                                        workspace.active_pane().clone()
16582                                    };
16583
16584                                    workspace.open_project_item(
16585                                        pane,
16586                                        target_buffer.clone(),
16587                                        true,
16588                                        true,
16589                                        window,
16590                                        cx,
16591                                    )
16592                                });
16593                            target_editor.update(cx, |target_editor, cx| {
16594                                // When selecting a definition in a different buffer, disable the nav history
16595                                // to avoid creating a history entry at the previous cursor location.
16596                                pane.update(cx, |pane, _| pane.disable_history());
16597                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16598                                pane.update(cx, |pane, _| pane.enable_history());
16599                            });
16600                        });
16601                    }
16602                    Navigated::Yes
16603                })
16604            }
16605        })
16606    }
16607
16608    fn compute_target_location(
16609        &self,
16610        lsp_location: lsp::Location,
16611        server_id: LanguageServerId,
16612        window: &mut Window,
16613        cx: &mut Context<Self>,
16614    ) -> Task<anyhow::Result<Option<Location>>> {
16615        let Some(project) = self.project.clone() else {
16616            return Task::ready(Ok(None));
16617        };
16618
16619        cx.spawn_in(window, async move |editor, cx| {
16620            let location_task = editor.update(cx, |_, cx| {
16621                project.update(cx, |project, cx| {
16622                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16623                })
16624            })?;
16625            let location = Some({
16626                let target_buffer_handle = location_task.await.context("open local buffer")?;
16627                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16628                    let target_start = target_buffer
16629                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16630                    let target_end = target_buffer
16631                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16632                    target_buffer.anchor_after(target_start)
16633                        ..target_buffer.anchor_before(target_end)
16634                })?;
16635                Location {
16636                    buffer: target_buffer_handle,
16637                    range,
16638                }
16639            });
16640            Ok(location)
16641        })
16642    }
16643
16644    pub fn find_all_references(
16645        &mut self,
16646        _: &FindAllReferences,
16647        window: &mut Window,
16648        cx: &mut Context<Self>,
16649    ) -> Option<Task<Result<Navigated>>> {
16650        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16651        let multi_buffer = self.buffer.read(cx);
16652        let head = selection.head();
16653
16654        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16655        let head_anchor = multi_buffer_snapshot.anchor_at(
16656            head,
16657            if head < selection.tail() {
16658                Bias::Right
16659            } else {
16660                Bias::Left
16661            },
16662        );
16663
16664        match self
16665            .find_all_references_task_sources
16666            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16667        {
16668            Ok(_) => {
16669                log::info!(
16670                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16671                );
16672                return None;
16673            }
16674            Err(i) => {
16675                self.find_all_references_task_sources.insert(i, head_anchor);
16676            }
16677        }
16678
16679        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16680        let workspace = self.workspace()?;
16681        let project = workspace.read(cx).project().clone();
16682        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16683        Some(cx.spawn_in(window, async move |editor, cx| {
16684            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16685                if let Ok(i) = editor
16686                    .find_all_references_task_sources
16687                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16688                {
16689                    editor.find_all_references_task_sources.remove(i);
16690                }
16691            });
16692
16693            let Some(locations) = references.await? else {
16694                return anyhow::Ok(Navigated::No);
16695            };
16696            let mut locations = cx.update(|_, cx| {
16697                locations
16698                    .into_iter()
16699                    .map(|location| {
16700                        let buffer = location.buffer.read(cx);
16701                        (location.buffer, location.range.to_point(buffer))
16702                    })
16703                    .into_group_map()
16704            })?;
16705            if locations.is_empty() {
16706                return anyhow::Ok(Navigated::No);
16707            }
16708            for ranges in locations.values_mut() {
16709                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16710                ranges.dedup();
16711            }
16712
16713            workspace.update_in(cx, |workspace, window, cx| {
16714                let target = locations
16715                    .iter()
16716                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16717                    .map(|(buffer, location)| {
16718                        buffer
16719                            .read(cx)
16720                            .text_for_range(location.clone())
16721                            .collect::<String>()
16722                    })
16723                    .filter(|text| !text.contains('\n'))
16724                    .unique()
16725                    .take(3)
16726                    .join(", ");
16727                let title = if target.is_empty() {
16728                    "References".to_owned()
16729                } else {
16730                    format!("References to {target}")
16731                };
16732                Self::open_locations_in_multibuffer(
16733                    workspace,
16734                    locations,
16735                    title,
16736                    false,
16737                    MultibufferSelectionMode::First,
16738                    window,
16739                    cx,
16740                );
16741                Navigated::Yes
16742            })
16743        }))
16744    }
16745
16746    /// Opens a multibuffer with the given project locations in it
16747    pub fn open_locations_in_multibuffer(
16748        workspace: &mut Workspace,
16749        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16750        title: String,
16751        split: bool,
16752        multibuffer_selection_mode: MultibufferSelectionMode,
16753        window: &mut Window,
16754        cx: &mut Context<Workspace>,
16755    ) {
16756        if locations.is_empty() {
16757            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16758            return;
16759        }
16760
16761        let capability = workspace.project().read(cx).capability();
16762        let mut ranges = <Vec<Range<Anchor>>>::new();
16763
16764        // a key to find existing multibuffer editors with the same set of locations
16765        // to prevent us from opening more and more multibuffer tabs for searches and the like
16766        let mut key = (title.clone(), vec![]);
16767        let excerpt_buffer = cx.new(|cx| {
16768            let key = &mut key.1;
16769            let mut multibuffer = MultiBuffer::new(capability);
16770            for (buffer, mut ranges_for_buffer) in locations {
16771                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16772                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16773                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16774                    PathKey::for_buffer(&buffer, cx),
16775                    buffer.clone(),
16776                    ranges_for_buffer,
16777                    multibuffer_context_lines(cx),
16778                    cx,
16779                );
16780                ranges.extend(new_ranges)
16781            }
16782
16783            multibuffer.with_title(title)
16784        });
16785        let existing = workspace.active_pane().update(cx, |pane, cx| {
16786            pane.items()
16787                .filter_map(|item| item.downcast::<Editor>())
16788                .find(|editor| {
16789                    editor
16790                        .read(cx)
16791                        .lookup_key
16792                        .as_ref()
16793                        .and_then(|it| {
16794                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16795                        })
16796                        .is_some_and(|it| *it == key)
16797                })
16798        });
16799        let editor = existing.unwrap_or_else(|| {
16800            cx.new(|cx| {
16801                let mut editor = Editor::for_multibuffer(
16802                    excerpt_buffer,
16803                    Some(workspace.project().clone()),
16804                    window,
16805                    cx,
16806                );
16807                editor.lookup_key = Some(Box::new(key));
16808                editor
16809            })
16810        });
16811        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
16812            MultibufferSelectionMode::First => {
16813                if let Some(first_range) = ranges.first() {
16814                    editor.change_selections(
16815                        SelectionEffects::no_scroll(),
16816                        window,
16817                        cx,
16818                        |selections| {
16819                            selections.clear_disjoint();
16820                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
16821                        },
16822                    );
16823                }
16824                editor.highlight_background::<Self>(
16825                    &ranges,
16826                    |theme| theme.colors().editor_highlighted_line_background,
16827                    cx,
16828                );
16829            }
16830            MultibufferSelectionMode::All => {
16831                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
16832                    selections.clear_disjoint();
16833                    selections.select_anchor_ranges(ranges);
16834                });
16835            }
16836        });
16837
16838        let item = Box::new(editor);
16839        let item_id = item.item_id();
16840
16841        if split {
16842            let pane = workspace.adjacent_pane(window, cx);
16843            workspace.add_item(pane, item, None, true, true, window, cx);
16844        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16845            let (preview_item_id, preview_item_idx) =
16846                workspace.active_pane().read_with(cx, |pane, _| {
16847                    (pane.preview_item_id(), pane.preview_item_idx())
16848                });
16849
16850            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16851
16852            if let Some(preview_item_id) = preview_item_id {
16853                workspace.active_pane().update(cx, |pane, cx| {
16854                    pane.remove_item(preview_item_id, false, false, window, cx);
16855                });
16856            }
16857        } else {
16858            workspace.add_item_to_active_pane(item, None, true, window, cx);
16859        }
16860        workspace.active_pane().update(cx, |pane, cx| {
16861            pane.set_preview_item_id(Some(item_id), cx);
16862        });
16863    }
16864
16865    pub fn rename(
16866        &mut self,
16867        _: &Rename,
16868        window: &mut Window,
16869        cx: &mut Context<Self>,
16870    ) -> Option<Task<Result<()>>> {
16871        use language::ToOffset as _;
16872
16873        let provider = self.semantics_provider.clone()?;
16874        let selection = self.selections.newest_anchor().clone();
16875        let (cursor_buffer, cursor_buffer_position) = self
16876            .buffer
16877            .read(cx)
16878            .text_anchor_for_position(selection.head(), cx)?;
16879        let (tail_buffer, cursor_buffer_position_end) = self
16880            .buffer
16881            .read(cx)
16882            .text_anchor_for_position(selection.tail(), cx)?;
16883        if tail_buffer != cursor_buffer {
16884            return None;
16885        }
16886
16887        let snapshot = cursor_buffer.read(cx).snapshot();
16888        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16889        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16890        let prepare_rename = provider
16891            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16892            .unwrap_or_else(|| Task::ready(Ok(None)));
16893        drop(snapshot);
16894
16895        Some(cx.spawn_in(window, async move |this, cx| {
16896            let rename_range = if let Some(range) = prepare_rename.await? {
16897                Some(range)
16898            } else {
16899                this.update(cx, |this, cx| {
16900                    let buffer = this.buffer.read(cx).snapshot(cx);
16901                    let mut buffer_highlights = this
16902                        .document_highlights_for_position(selection.head(), &buffer)
16903                        .filter(|highlight| {
16904                            highlight.start.excerpt_id == selection.head().excerpt_id
16905                                && highlight.end.excerpt_id == selection.head().excerpt_id
16906                        });
16907                    buffer_highlights
16908                        .next()
16909                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16910                })?
16911            };
16912            if let Some(rename_range) = rename_range {
16913                this.update_in(cx, |this, window, cx| {
16914                    let snapshot = cursor_buffer.read(cx).snapshot();
16915                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16916                    let cursor_offset_in_rename_range =
16917                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16918                    let cursor_offset_in_rename_range_end =
16919                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16920
16921                    this.take_rename(false, window, cx);
16922                    let buffer = this.buffer.read(cx).read(cx);
16923                    let cursor_offset = selection.head().to_offset(&buffer);
16924                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16925                    let rename_end = rename_start + rename_buffer_range.len();
16926                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16927                    let mut old_highlight_id = None;
16928                    let old_name: Arc<str> = buffer
16929                        .chunks(rename_start..rename_end, true)
16930                        .map(|chunk| {
16931                            if old_highlight_id.is_none() {
16932                                old_highlight_id = chunk.syntax_highlight_id;
16933                            }
16934                            chunk.text
16935                        })
16936                        .collect::<String>()
16937                        .into();
16938
16939                    drop(buffer);
16940
16941                    // Position the selection in the rename editor so that it matches the current selection.
16942                    this.show_local_selections = false;
16943                    let rename_editor = cx.new(|cx| {
16944                        let mut editor = Editor::single_line(window, cx);
16945                        editor.buffer.update(cx, |buffer, cx| {
16946                            buffer.edit([(0..0, old_name.clone())], None, cx)
16947                        });
16948                        let rename_selection_range = match cursor_offset_in_rename_range
16949                            .cmp(&cursor_offset_in_rename_range_end)
16950                        {
16951                            Ordering::Equal => {
16952                                editor.select_all(&SelectAll, window, cx);
16953                                return editor;
16954                            }
16955                            Ordering::Less => {
16956                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16957                            }
16958                            Ordering::Greater => {
16959                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16960                            }
16961                        };
16962                        if rename_selection_range.end > old_name.len() {
16963                            editor.select_all(&SelectAll, window, cx);
16964                        } else {
16965                            editor.change_selections(Default::default(), window, cx, |s| {
16966                                s.select_ranges([rename_selection_range]);
16967                            });
16968                        }
16969                        editor
16970                    });
16971                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16972                        if e == &EditorEvent::Focused {
16973                            cx.emit(EditorEvent::FocusedIn)
16974                        }
16975                    })
16976                    .detach();
16977
16978                    let write_highlights =
16979                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16980                    let read_highlights =
16981                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16982                    let ranges = write_highlights
16983                        .iter()
16984                        .flat_map(|(_, ranges)| ranges.iter())
16985                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16986                        .cloned()
16987                        .collect();
16988
16989                    this.highlight_text::<Rename>(
16990                        ranges,
16991                        HighlightStyle {
16992                            fade_out: Some(0.6),
16993                            ..Default::default()
16994                        },
16995                        cx,
16996                    );
16997                    let rename_focus_handle = rename_editor.focus_handle(cx);
16998                    window.focus(&rename_focus_handle);
16999                    let block_id = this.insert_blocks(
17000                        [BlockProperties {
17001                            style: BlockStyle::Flex,
17002                            placement: BlockPlacement::Below(range.start),
17003                            height: Some(1),
17004                            render: Arc::new({
17005                                let rename_editor = rename_editor.clone();
17006                                move |cx: &mut BlockContext| {
17007                                    let mut text_style = cx.editor_style.text.clone();
17008                                    if let Some(highlight_style) = old_highlight_id
17009                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17010                                    {
17011                                        text_style = text_style.highlight(highlight_style);
17012                                    }
17013                                    div()
17014                                        .block_mouse_except_scroll()
17015                                        .pl(cx.anchor_x)
17016                                        .child(EditorElement::new(
17017                                            &rename_editor,
17018                                            EditorStyle {
17019                                                background: cx.theme().system().transparent,
17020                                                local_player: cx.editor_style.local_player,
17021                                                text: text_style,
17022                                                scrollbar_width: cx.editor_style.scrollbar_width,
17023                                                syntax: cx.editor_style.syntax.clone(),
17024                                                status: cx.editor_style.status.clone(),
17025                                                inlay_hints_style: HighlightStyle {
17026                                                    font_weight: Some(FontWeight::BOLD),
17027                                                    ..make_inlay_hints_style(cx.app)
17028                                                },
17029                                                edit_prediction_styles: make_suggestion_styles(
17030                                                    cx.app,
17031                                                ),
17032                                                ..EditorStyle::default()
17033                                            },
17034                                        ))
17035                                        .into_any_element()
17036                                }
17037                            }),
17038                            priority: 0,
17039                        }],
17040                        Some(Autoscroll::fit()),
17041                        cx,
17042                    )[0];
17043                    this.pending_rename = Some(RenameState {
17044                        range,
17045                        old_name,
17046                        editor: rename_editor,
17047                        block_id,
17048                    });
17049                })?;
17050            }
17051
17052            Ok(())
17053        }))
17054    }
17055
17056    pub fn confirm_rename(
17057        &mut self,
17058        _: &ConfirmRename,
17059        window: &mut Window,
17060        cx: &mut Context<Self>,
17061    ) -> Option<Task<Result<()>>> {
17062        let rename = self.take_rename(false, window, cx)?;
17063        let workspace = self.workspace()?.downgrade();
17064        let (buffer, start) = self
17065            .buffer
17066            .read(cx)
17067            .text_anchor_for_position(rename.range.start, cx)?;
17068        let (end_buffer, _) = self
17069            .buffer
17070            .read(cx)
17071            .text_anchor_for_position(rename.range.end, cx)?;
17072        if buffer != end_buffer {
17073            return None;
17074        }
17075
17076        let old_name = rename.old_name;
17077        let new_name = rename.editor.read(cx).text(cx);
17078
17079        let rename = self.semantics_provider.as_ref()?.perform_rename(
17080            &buffer,
17081            start,
17082            new_name.clone(),
17083            cx,
17084        )?;
17085
17086        Some(cx.spawn_in(window, async move |editor, cx| {
17087            let project_transaction = rename.await?;
17088            Self::open_project_transaction(
17089                &editor,
17090                workspace,
17091                project_transaction,
17092                format!("Rename: {}{}", old_name, new_name),
17093                cx,
17094            )
17095            .await?;
17096
17097            editor.update(cx, |editor, cx| {
17098                editor.refresh_document_highlights(cx);
17099            })?;
17100            Ok(())
17101        }))
17102    }
17103
17104    fn take_rename(
17105        &mut self,
17106        moving_cursor: bool,
17107        window: &mut Window,
17108        cx: &mut Context<Self>,
17109    ) -> Option<RenameState> {
17110        let rename = self.pending_rename.take()?;
17111        if rename.editor.focus_handle(cx).is_focused(window) {
17112            window.focus(&self.focus_handle);
17113        }
17114
17115        self.remove_blocks(
17116            [rename.block_id].into_iter().collect(),
17117            Some(Autoscroll::fit()),
17118            cx,
17119        );
17120        self.clear_highlights::<Rename>(cx);
17121        self.show_local_selections = true;
17122
17123        if moving_cursor {
17124            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17125                editor
17126                    .selections
17127                    .newest::<usize>(&editor.display_snapshot(cx))
17128                    .head()
17129            });
17130
17131            // Update the selection to match the position of the selection inside
17132            // the rename editor.
17133            let snapshot = self.buffer.read(cx).read(cx);
17134            let rename_range = rename.range.to_offset(&snapshot);
17135            let cursor_in_editor = snapshot
17136                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17137                .min(rename_range.end);
17138            drop(snapshot);
17139
17140            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17141                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17142            });
17143        } else {
17144            self.refresh_document_highlights(cx);
17145        }
17146
17147        Some(rename)
17148    }
17149
17150    pub fn pending_rename(&self) -> Option<&RenameState> {
17151        self.pending_rename.as_ref()
17152    }
17153
17154    fn format(
17155        &mut self,
17156        _: &Format,
17157        window: &mut Window,
17158        cx: &mut Context<Self>,
17159    ) -> Option<Task<Result<()>>> {
17160        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17161
17162        let project = match &self.project {
17163            Some(project) => project.clone(),
17164            None => return None,
17165        };
17166
17167        Some(self.perform_format(
17168            project,
17169            FormatTrigger::Manual,
17170            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17171            window,
17172            cx,
17173        ))
17174    }
17175
17176    fn format_selections(
17177        &mut self,
17178        _: &FormatSelections,
17179        window: &mut Window,
17180        cx: &mut Context<Self>,
17181    ) -> Option<Task<Result<()>>> {
17182        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17183
17184        let project = match &self.project {
17185            Some(project) => project.clone(),
17186            None => return None,
17187        };
17188
17189        let ranges = self
17190            .selections
17191            .all_adjusted(&self.display_snapshot(cx))
17192            .into_iter()
17193            .map(|selection| selection.range())
17194            .collect_vec();
17195
17196        Some(self.perform_format(
17197            project,
17198            FormatTrigger::Manual,
17199            FormatTarget::Ranges(ranges),
17200            window,
17201            cx,
17202        ))
17203    }
17204
17205    fn perform_format(
17206        &mut self,
17207        project: Entity<Project>,
17208        trigger: FormatTrigger,
17209        target: FormatTarget,
17210        window: &mut Window,
17211        cx: &mut Context<Self>,
17212    ) -> Task<Result<()>> {
17213        let buffer = self.buffer.clone();
17214        let (buffers, target) = match target {
17215            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17216            FormatTarget::Ranges(selection_ranges) => {
17217                let multi_buffer = buffer.read(cx);
17218                let snapshot = multi_buffer.read(cx);
17219                let mut buffers = HashSet::default();
17220                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17221                    BTreeMap::new();
17222                for selection_range in selection_ranges {
17223                    for (buffer, buffer_range, _) in
17224                        snapshot.range_to_buffer_ranges(selection_range)
17225                    {
17226                        let buffer_id = buffer.remote_id();
17227                        let start = buffer.anchor_before(buffer_range.start);
17228                        let end = buffer.anchor_after(buffer_range.end);
17229                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17230                        buffer_id_to_ranges
17231                            .entry(buffer_id)
17232                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17233                            .or_insert_with(|| vec![start..end]);
17234                    }
17235                }
17236                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17237            }
17238        };
17239
17240        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17241        let selections_prev = transaction_id_prev
17242            .and_then(|transaction_id_prev| {
17243                // default to selections as they were after the last edit, if we have them,
17244                // instead of how they are now.
17245                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17246                // will take you back to where you made the last edit, instead of staying where you scrolled
17247                self.selection_history
17248                    .transaction(transaction_id_prev)
17249                    .map(|t| t.0.clone())
17250            })
17251            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17252
17253        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17254        let format = project.update(cx, |project, cx| {
17255            project.format(buffers, target, true, trigger, cx)
17256        });
17257
17258        cx.spawn_in(window, async move |editor, cx| {
17259            let transaction = futures::select_biased! {
17260                transaction = format.log_err().fuse() => transaction,
17261                () = timeout => {
17262                    log::warn!("timed out waiting for formatting");
17263                    None
17264                }
17265            };
17266
17267            buffer
17268                .update(cx, |buffer, cx| {
17269                    if let Some(transaction) = transaction
17270                        && !buffer.is_singleton()
17271                    {
17272                        buffer.push_transaction(&transaction.0, cx);
17273                    }
17274                    cx.notify();
17275                })
17276                .ok();
17277
17278            if let Some(transaction_id_now) =
17279                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17280            {
17281                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17282                if has_new_transaction {
17283                    _ = editor.update(cx, |editor, _| {
17284                        editor
17285                            .selection_history
17286                            .insert_transaction(transaction_id_now, selections_prev);
17287                    });
17288                }
17289            }
17290
17291            Ok(())
17292        })
17293    }
17294
17295    fn organize_imports(
17296        &mut self,
17297        _: &OrganizeImports,
17298        window: &mut Window,
17299        cx: &mut Context<Self>,
17300    ) -> Option<Task<Result<()>>> {
17301        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17302        let project = match &self.project {
17303            Some(project) => project.clone(),
17304            None => return None,
17305        };
17306        Some(self.perform_code_action_kind(
17307            project,
17308            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17309            window,
17310            cx,
17311        ))
17312    }
17313
17314    fn perform_code_action_kind(
17315        &mut self,
17316        project: Entity<Project>,
17317        kind: CodeActionKind,
17318        window: &mut Window,
17319        cx: &mut Context<Self>,
17320    ) -> Task<Result<()>> {
17321        let buffer = self.buffer.clone();
17322        let buffers = buffer.read(cx).all_buffers();
17323        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17324        let apply_action = project.update(cx, |project, cx| {
17325            project.apply_code_action_kind(buffers, kind, true, cx)
17326        });
17327        cx.spawn_in(window, async move |_, cx| {
17328            let transaction = futures::select_biased! {
17329                () = timeout => {
17330                    log::warn!("timed out waiting for executing code action");
17331                    None
17332                }
17333                transaction = apply_action.log_err().fuse() => transaction,
17334            };
17335            buffer
17336                .update(cx, |buffer, cx| {
17337                    // check if we need this
17338                    if let Some(transaction) = transaction
17339                        && !buffer.is_singleton()
17340                    {
17341                        buffer.push_transaction(&transaction.0, cx);
17342                    }
17343                    cx.notify();
17344                })
17345                .ok();
17346            Ok(())
17347        })
17348    }
17349
17350    pub fn restart_language_server(
17351        &mut self,
17352        _: &RestartLanguageServer,
17353        _: &mut Window,
17354        cx: &mut Context<Self>,
17355    ) {
17356        if let Some(project) = self.project.clone() {
17357            self.buffer.update(cx, |multi_buffer, cx| {
17358                project.update(cx, |project, cx| {
17359                    project.restart_language_servers_for_buffers(
17360                        multi_buffer.all_buffers().into_iter().collect(),
17361                        HashSet::default(),
17362                        cx,
17363                    );
17364                });
17365            })
17366        }
17367    }
17368
17369    pub fn stop_language_server(
17370        &mut self,
17371        _: &StopLanguageServer,
17372        _: &mut Window,
17373        cx: &mut Context<Self>,
17374    ) {
17375        if let Some(project) = self.project.clone() {
17376            self.buffer.update(cx, |multi_buffer, cx| {
17377                project.update(cx, |project, cx| {
17378                    project.stop_language_servers_for_buffers(
17379                        multi_buffer.all_buffers().into_iter().collect(),
17380                        HashSet::default(),
17381                        cx,
17382                    );
17383                });
17384            });
17385            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17386        }
17387    }
17388
17389    fn cancel_language_server_work(
17390        workspace: &mut Workspace,
17391        _: &actions::CancelLanguageServerWork,
17392        _: &mut Window,
17393        cx: &mut Context<Workspace>,
17394    ) {
17395        let project = workspace.project();
17396        let buffers = workspace
17397            .active_item(cx)
17398            .and_then(|item| item.act_as::<Editor>(cx))
17399            .map_or(HashSet::default(), |editor| {
17400                editor.read(cx).buffer.read(cx).all_buffers()
17401            });
17402        project.update(cx, |project, cx| {
17403            project.cancel_language_server_work_for_buffers(buffers, cx);
17404        });
17405    }
17406
17407    fn show_character_palette(
17408        &mut self,
17409        _: &ShowCharacterPalette,
17410        window: &mut Window,
17411        _: &mut Context<Self>,
17412    ) {
17413        window.show_character_palette();
17414    }
17415
17416    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17417        if !self.diagnostics_enabled() {
17418            return;
17419        }
17420
17421        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17422            let buffer = self.buffer.read(cx).snapshot(cx);
17423            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17424            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17425            let is_valid = buffer
17426                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17427                .any(|entry| {
17428                    entry.diagnostic.is_primary
17429                        && !entry.range.is_empty()
17430                        && entry.range.start == primary_range_start
17431                        && entry.diagnostic.message == active_diagnostics.active_message
17432                });
17433
17434            if !is_valid {
17435                self.dismiss_diagnostics(cx);
17436            }
17437        }
17438    }
17439
17440    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17441        match &self.active_diagnostics {
17442            ActiveDiagnostic::Group(group) => Some(group),
17443            _ => None,
17444        }
17445    }
17446
17447    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17448        if !self.diagnostics_enabled() {
17449            return;
17450        }
17451        self.dismiss_diagnostics(cx);
17452        self.active_diagnostics = ActiveDiagnostic::All;
17453    }
17454
17455    fn activate_diagnostics(
17456        &mut self,
17457        buffer_id: BufferId,
17458        diagnostic: DiagnosticEntryRef<'_, usize>,
17459        window: &mut Window,
17460        cx: &mut Context<Self>,
17461    ) {
17462        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17463            return;
17464        }
17465        self.dismiss_diagnostics(cx);
17466        let snapshot = self.snapshot(window, cx);
17467        let buffer = self.buffer.read(cx).snapshot(cx);
17468        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17469            return;
17470        };
17471
17472        let diagnostic_group = buffer
17473            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17474            .collect::<Vec<_>>();
17475
17476        let blocks =
17477            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17478
17479        let blocks = self.display_map.update(cx, |display_map, cx| {
17480            display_map.insert_blocks(blocks, cx).into_iter().collect()
17481        });
17482        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17483            active_range: buffer.anchor_before(diagnostic.range.start)
17484                ..buffer.anchor_after(diagnostic.range.end),
17485            active_message: diagnostic.diagnostic.message.clone(),
17486            group_id: diagnostic.diagnostic.group_id,
17487            blocks,
17488        });
17489        cx.notify();
17490    }
17491
17492    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17493        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17494            return;
17495        };
17496
17497        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17498        if let ActiveDiagnostic::Group(group) = prev {
17499            self.display_map.update(cx, |display_map, cx| {
17500                display_map.remove_blocks(group.blocks, cx);
17501            });
17502            cx.notify();
17503        }
17504    }
17505
17506    /// Disable inline diagnostics rendering for this editor.
17507    pub fn disable_inline_diagnostics(&mut self) {
17508        self.inline_diagnostics_enabled = false;
17509        self.inline_diagnostics_update = Task::ready(());
17510        self.inline_diagnostics.clear();
17511    }
17512
17513    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17514        self.diagnostics_enabled = false;
17515        self.dismiss_diagnostics(cx);
17516        self.inline_diagnostics_update = Task::ready(());
17517        self.inline_diagnostics.clear();
17518    }
17519
17520    pub fn disable_word_completions(&mut self) {
17521        self.word_completions_enabled = false;
17522    }
17523
17524    pub fn diagnostics_enabled(&self) -> bool {
17525        self.diagnostics_enabled && self.mode.is_full()
17526    }
17527
17528    pub fn inline_diagnostics_enabled(&self) -> bool {
17529        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17530    }
17531
17532    pub fn show_inline_diagnostics(&self) -> bool {
17533        self.show_inline_diagnostics
17534    }
17535
17536    pub fn toggle_inline_diagnostics(
17537        &mut self,
17538        _: &ToggleInlineDiagnostics,
17539        window: &mut Window,
17540        cx: &mut Context<Editor>,
17541    ) {
17542        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17543        self.refresh_inline_diagnostics(false, window, cx);
17544    }
17545
17546    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17547        self.diagnostics_max_severity = severity;
17548        self.display_map.update(cx, |display_map, _| {
17549            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17550        });
17551    }
17552
17553    pub fn toggle_diagnostics(
17554        &mut self,
17555        _: &ToggleDiagnostics,
17556        window: &mut Window,
17557        cx: &mut Context<Editor>,
17558    ) {
17559        if !self.diagnostics_enabled() {
17560            return;
17561        }
17562
17563        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17564            EditorSettings::get_global(cx)
17565                .diagnostics_max_severity
17566                .filter(|severity| severity != &DiagnosticSeverity::Off)
17567                .unwrap_or(DiagnosticSeverity::Hint)
17568        } else {
17569            DiagnosticSeverity::Off
17570        };
17571        self.set_max_diagnostics_severity(new_severity, cx);
17572        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17573            self.active_diagnostics = ActiveDiagnostic::None;
17574            self.inline_diagnostics_update = Task::ready(());
17575            self.inline_diagnostics.clear();
17576        } else {
17577            self.refresh_inline_diagnostics(false, window, cx);
17578        }
17579
17580        cx.notify();
17581    }
17582
17583    pub fn toggle_minimap(
17584        &mut self,
17585        _: &ToggleMinimap,
17586        window: &mut Window,
17587        cx: &mut Context<Editor>,
17588    ) {
17589        if self.supports_minimap(cx) {
17590            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17591        }
17592    }
17593
17594    fn refresh_inline_diagnostics(
17595        &mut self,
17596        debounce: bool,
17597        window: &mut Window,
17598        cx: &mut Context<Self>,
17599    ) {
17600        let max_severity = ProjectSettings::get_global(cx)
17601            .diagnostics
17602            .inline
17603            .max_severity
17604            .unwrap_or(self.diagnostics_max_severity);
17605
17606        if !self.inline_diagnostics_enabled()
17607            || !self.show_inline_diagnostics
17608            || max_severity == DiagnosticSeverity::Off
17609        {
17610            self.inline_diagnostics_update = Task::ready(());
17611            self.inline_diagnostics.clear();
17612            return;
17613        }
17614
17615        let debounce_ms = ProjectSettings::get_global(cx)
17616            .diagnostics
17617            .inline
17618            .update_debounce_ms;
17619        let debounce = if debounce && debounce_ms > 0 {
17620            Some(Duration::from_millis(debounce_ms))
17621        } else {
17622            None
17623        };
17624        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17625            if let Some(debounce) = debounce {
17626                cx.background_executor().timer(debounce).await;
17627            }
17628            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17629                editor
17630                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17631                    .ok()
17632            }) else {
17633                return;
17634            };
17635
17636            let new_inline_diagnostics = cx
17637                .background_spawn(async move {
17638                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17639                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17640                        let message = diagnostic_entry
17641                            .diagnostic
17642                            .message
17643                            .split_once('\n')
17644                            .map(|(line, _)| line)
17645                            .map(SharedString::new)
17646                            .unwrap_or_else(|| {
17647                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17648                            });
17649                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17650                        let (Ok(i) | Err(i)) = inline_diagnostics
17651                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17652                        inline_diagnostics.insert(
17653                            i,
17654                            (
17655                                start_anchor,
17656                                InlineDiagnostic {
17657                                    message,
17658                                    group_id: diagnostic_entry.diagnostic.group_id,
17659                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17660                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17661                                    severity: diagnostic_entry.diagnostic.severity,
17662                                },
17663                            ),
17664                        );
17665                    }
17666                    inline_diagnostics
17667                })
17668                .await;
17669
17670            editor
17671                .update(cx, |editor, cx| {
17672                    editor.inline_diagnostics = new_inline_diagnostics;
17673                    cx.notify();
17674                })
17675                .ok();
17676        });
17677    }
17678
17679    fn pull_diagnostics(
17680        &mut self,
17681        buffer_id: Option<BufferId>,
17682        window: &Window,
17683        cx: &mut Context<Self>,
17684    ) -> Option<()> {
17685        if self.ignore_lsp_data() {
17686            return None;
17687        }
17688        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17689            .diagnostics
17690            .lsp_pull_diagnostics;
17691        if !pull_diagnostics_settings.enabled {
17692            return None;
17693        }
17694        let project = self.project()?.downgrade();
17695        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17696        let mut buffers = self.buffer.read(cx).all_buffers();
17697        buffers.retain(|buffer| {
17698            let buffer_id_to_retain = buffer.read(cx).remote_id();
17699            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17700                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17701        });
17702        if buffers.is_empty() {
17703            self.pull_diagnostics_task = Task::ready(());
17704            return None;
17705        }
17706
17707        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17708            cx.background_executor().timer(debounce).await;
17709
17710            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17711                buffers
17712                    .into_iter()
17713                    .filter_map(|buffer| {
17714                        project
17715                            .update(cx, |project, cx| {
17716                                project.lsp_store().update(cx, |lsp_store, cx| {
17717                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17718                                })
17719                            })
17720                            .ok()
17721                    })
17722                    .collect::<FuturesUnordered<_>>()
17723            }) else {
17724                return;
17725            };
17726
17727            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17728                match pull_task {
17729                    Ok(()) => {
17730                        if editor
17731                            .update_in(cx, |editor, window, cx| {
17732                                editor.update_diagnostics_state(window, cx);
17733                            })
17734                            .is_err()
17735                        {
17736                            return;
17737                        }
17738                    }
17739                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17740                }
17741            }
17742        });
17743
17744        Some(())
17745    }
17746
17747    pub fn set_selections_from_remote(
17748        &mut self,
17749        selections: Vec<Selection<Anchor>>,
17750        pending_selection: Option<Selection<Anchor>>,
17751        window: &mut Window,
17752        cx: &mut Context<Self>,
17753    ) {
17754        let old_cursor_position = self.selections.newest_anchor().head();
17755        self.selections.change_with(cx, |s| {
17756            s.select_anchors(selections);
17757            if let Some(pending_selection) = pending_selection {
17758                s.set_pending(pending_selection, SelectMode::Character);
17759            } else {
17760                s.clear_pending();
17761            }
17762        });
17763        self.selections_did_change(
17764            false,
17765            &old_cursor_position,
17766            SelectionEffects::default(),
17767            window,
17768            cx,
17769        );
17770    }
17771
17772    pub fn transact(
17773        &mut self,
17774        window: &mut Window,
17775        cx: &mut Context<Self>,
17776        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17777    ) -> Option<TransactionId> {
17778        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17779            this.start_transaction_at(Instant::now(), window, cx);
17780            update(this, window, cx);
17781            this.end_transaction_at(Instant::now(), cx)
17782        })
17783    }
17784
17785    pub fn start_transaction_at(
17786        &mut self,
17787        now: Instant,
17788        window: &mut Window,
17789        cx: &mut Context<Self>,
17790    ) -> Option<TransactionId> {
17791        self.end_selection(window, cx);
17792        if let Some(tx_id) = self
17793            .buffer
17794            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17795        {
17796            self.selection_history
17797                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17798            cx.emit(EditorEvent::TransactionBegun {
17799                transaction_id: tx_id,
17800            });
17801            Some(tx_id)
17802        } else {
17803            None
17804        }
17805    }
17806
17807    pub fn end_transaction_at(
17808        &mut self,
17809        now: Instant,
17810        cx: &mut Context<Self>,
17811    ) -> Option<TransactionId> {
17812        if let Some(transaction_id) = self
17813            .buffer
17814            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17815        {
17816            if let Some((_, end_selections)) =
17817                self.selection_history.transaction_mut(transaction_id)
17818            {
17819                *end_selections = Some(self.selections.disjoint_anchors_arc());
17820            } else {
17821                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17822            }
17823
17824            cx.emit(EditorEvent::Edited { transaction_id });
17825            Some(transaction_id)
17826        } else {
17827            None
17828        }
17829    }
17830
17831    pub fn modify_transaction_selection_history(
17832        &mut self,
17833        transaction_id: TransactionId,
17834        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17835    ) -> bool {
17836        self.selection_history
17837            .transaction_mut(transaction_id)
17838            .map(modify)
17839            .is_some()
17840    }
17841
17842    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17843        if self.selection_mark_mode {
17844            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17845                s.move_with(|_, sel| {
17846                    sel.collapse_to(sel.head(), SelectionGoal::None);
17847                });
17848            })
17849        }
17850        self.selection_mark_mode = true;
17851        cx.notify();
17852    }
17853
17854    pub fn swap_selection_ends(
17855        &mut self,
17856        _: &actions::SwapSelectionEnds,
17857        window: &mut Window,
17858        cx: &mut Context<Self>,
17859    ) {
17860        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17861            s.move_with(|_, sel| {
17862                if sel.start != sel.end {
17863                    sel.reversed = !sel.reversed
17864                }
17865            });
17866        });
17867        self.request_autoscroll(Autoscroll::newest(), cx);
17868        cx.notify();
17869    }
17870
17871    pub fn toggle_focus(
17872        workspace: &mut Workspace,
17873        _: &actions::ToggleFocus,
17874        window: &mut Window,
17875        cx: &mut Context<Workspace>,
17876    ) {
17877        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17878            return;
17879        };
17880        workspace.activate_item(&item, true, true, window, cx);
17881    }
17882
17883    pub fn toggle_fold(
17884        &mut self,
17885        _: &actions::ToggleFold,
17886        window: &mut Window,
17887        cx: &mut Context<Self>,
17888    ) {
17889        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
17890            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17891            let selection = self.selections.newest::<Point>(&display_map);
17892
17893            let range = if selection.is_empty() {
17894                let point = selection.head().to_display_point(&display_map);
17895                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17896                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17897                    .to_point(&display_map);
17898                start..end
17899            } else {
17900                selection.range()
17901            };
17902            if display_map.folds_in_range(range).next().is_some() {
17903                self.unfold_lines(&Default::default(), window, cx)
17904            } else {
17905                self.fold(&Default::default(), window, cx)
17906            }
17907        } else {
17908            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17909            let buffer_ids: HashSet<_> = self
17910                .selections
17911                .disjoint_anchor_ranges()
17912                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17913                .collect();
17914
17915            let should_unfold = buffer_ids
17916                .iter()
17917                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17918
17919            for buffer_id in buffer_ids {
17920                if should_unfold {
17921                    self.unfold_buffer(buffer_id, cx);
17922                } else {
17923                    self.fold_buffer(buffer_id, cx);
17924                }
17925            }
17926        }
17927    }
17928
17929    pub fn toggle_fold_recursive(
17930        &mut self,
17931        _: &actions::ToggleFoldRecursive,
17932        window: &mut Window,
17933        cx: &mut Context<Self>,
17934    ) {
17935        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
17936
17937        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17938        let range = if selection.is_empty() {
17939            let point = selection.head().to_display_point(&display_map);
17940            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17941            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17942                .to_point(&display_map);
17943            start..end
17944        } else {
17945            selection.range()
17946        };
17947        if display_map.folds_in_range(range).next().is_some() {
17948            self.unfold_recursive(&Default::default(), window, cx)
17949        } else {
17950            self.fold_recursive(&Default::default(), window, cx)
17951        }
17952    }
17953
17954    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17955        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
17956            let mut to_fold = Vec::new();
17957            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17958            let selections = self.selections.all_adjusted(&display_map);
17959
17960            for selection in selections {
17961                let range = selection.range().sorted();
17962                let buffer_start_row = range.start.row;
17963
17964                if range.start.row != range.end.row {
17965                    let mut found = false;
17966                    let mut row = range.start.row;
17967                    while row <= range.end.row {
17968                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17969                        {
17970                            found = true;
17971                            row = crease.range().end.row + 1;
17972                            to_fold.push(crease);
17973                        } else {
17974                            row += 1
17975                        }
17976                    }
17977                    if found {
17978                        continue;
17979                    }
17980                }
17981
17982                for row in (0..=range.start.row).rev() {
17983                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17984                        && crease.range().end.row >= buffer_start_row
17985                    {
17986                        to_fold.push(crease);
17987                        if row <= range.start.row {
17988                            break;
17989                        }
17990                    }
17991                }
17992            }
17993
17994            self.fold_creases(to_fold, true, window, cx);
17995        } else {
17996            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17997            let buffer_ids = self
17998                .selections
17999                .disjoint_anchor_ranges()
18000                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18001                .collect::<HashSet<_>>();
18002            for buffer_id in buffer_ids {
18003                self.fold_buffer(buffer_id, cx);
18004            }
18005        }
18006    }
18007
18008    pub fn toggle_fold_all(
18009        &mut self,
18010        _: &actions::ToggleFoldAll,
18011        window: &mut Window,
18012        cx: &mut Context<Self>,
18013    ) {
18014        if self.buffer.read(cx).is_singleton() {
18015            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18016            let has_folds = display_map
18017                .folds_in_range(0..display_map.buffer_snapshot().len())
18018                .next()
18019                .is_some();
18020
18021            if has_folds {
18022                self.unfold_all(&actions::UnfoldAll, window, cx);
18023            } else {
18024                self.fold_all(&actions::FoldAll, window, cx);
18025            }
18026        } else {
18027            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18028            let should_unfold = buffer_ids
18029                .iter()
18030                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18031
18032            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18033                editor
18034                    .update_in(cx, |editor, _, cx| {
18035                        for buffer_id in buffer_ids {
18036                            if should_unfold {
18037                                editor.unfold_buffer(buffer_id, cx);
18038                            } else {
18039                                editor.fold_buffer(buffer_id, cx);
18040                            }
18041                        }
18042                    })
18043                    .ok();
18044            });
18045        }
18046    }
18047
18048    fn fold_at_level(
18049        &mut self,
18050        fold_at: &FoldAtLevel,
18051        window: &mut Window,
18052        cx: &mut Context<Self>,
18053    ) {
18054        if !self.buffer.read(cx).is_singleton() {
18055            return;
18056        }
18057
18058        let fold_at_level = fold_at.0;
18059        let snapshot = self.buffer.read(cx).snapshot(cx);
18060        let mut to_fold = Vec::new();
18061        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18062
18063        let row_ranges_to_keep: Vec<Range<u32>> = self
18064            .selections
18065            .all::<Point>(&self.display_snapshot(cx))
18066            .into_iter()
18067            .map(|sel| sel.start.row..sel.end.row)
18068            .collect();
18069
18070        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18071            while start_row < end_row {
18072                match self
18073                    .snapshot(window, cx)
18074                    .crease_for_buffer_row(MultiBufferRow(start_row))
18075                {
18076                    Some(crease) => {
18077                        let nested_start_row = crease.range().start.row + 1;
18078                        let nested_end_row = crease.range().end.row;
18079
18080                        if current_level < fold_at_level {
18081                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18082                        } else if current_level == fold_at_level {
18083                            // Fold iff there is no selection completely contained within the fold region
18084                            if !row_ranges_to_keep.iter().any(|selection| {
18085                                selection.end >= nested_start_row
18086                                    && selection.start <= nested_end_row
18087                            }) {
18088                                to_fold.push(crease);
18089                            }
18090                        }
18091
18092                        start_row = nested_end_row + 1;
18093                    }
18094                    None => start_row += 1,
18095                }
18096            }
18097        }
18098
18099        self.fold_creases(to_fold, true, window, cx);
18100    }
18101
18102    pub fn fold_at_level_1(
18103        &mut self,
18104        _: &actions::FoldAtLevel1,
18105        window: &mut Window,
18106        cx: &mut Context<Self>,
18107    ) {
18108        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18109    }
18110
18111    pub fn fold_at_level_2(
18112        &mut self,
18113        _: &actions::FoldAtLevel2,
18114        window: &mut Window,
18115        cx: &mut Context<Self>,
18116    ) {
18117        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18118    }
18119
18120    pub fn fold_at_level_3(
18121        &mut self,
18122        _: &actions::FoldAtLevel3,
18123        window: &mut Window,
18124        cx: &mut Context<Self>,
18125    ) {
18126        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18127    }
18128
18129    pub fn fold_at_level_4(
18130        &mut self,
18131        _: &actions::FoldAtLevel4,
18132        window: &mut Window,
18133        cx: &mut Context<Self>,
18134    ) {
18135        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18136    }
18137
18138    pub fn fold_at_level_5(
18139        &mut self,
18140        _: &actions::FoldAtLevel5,
18141        window: &mut Window,
18142        cx: &mut Context<Self>,
18143    ) {
18144        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18145    }
18146
18147    pub fn fold_at_level_6(
18148        &mut self,
18149        _: &actions::FoldAtLevel6,
18150        window: &mut Window,
18151        cx: &mut Context<Self>,
18152    ) {
18153        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18154    }
18155
18156    pub fn fold_at_level_7(
18157        &mut self,
18158        _: &actions::FoldAtLevel7,
18159        window: &mut Window,
18160        cx: &mut Context<Self>,
18161    ) {
18162        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18163    }
18164
18165    pub fn fold_at_level_8(
18166        &mut self,
18167        _: &actions::FoldAtLevel8,
18168        window: &mut Window,
18169        cx: &mut Context<Self>,
18170    ) {
18171        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18172    }
18173
18174    pub fn fold_at_level_9(
18175        &mut self,
18176        _: &actions::FoldAtLevel9,
18177        window: &mut Window,
18178        cx: &mut Context<Self>,
18179    ) {
18180        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18181    }
18182
18183    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18184        if self.buffer.read(cx).is_singleton() {
18185            let mut fold_ranges = Vec::new();
18186            let snapshot = self.buffer.read(cx).snapshot(cx);
18187
18188            for row in 0..snapshot.max_row().0 {
18189                if let Some(foldable_range) = self
18190                    .snapshot(window, cx)
18191                    .crease_for_buffer_row(MultiBufferRow(row))
18192                {
18193                    fold_ranges.push(foldable_range);
18194                }
18195            }
18196
18197            self.fold_creases(fold_ranges, true, window, cx);
18198        } else {
18199            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18200                editor
18201                    .update_in(cx, |editor, _, cx| {
18202                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18203                            editor.fold_buffer(buffer_id, cx);
18204                        }
18205                    })
18206                    .ok();
18207            });
18208        }
18209    }
18210
18211    pub fn fold_function_bodies(
18212        &mut self,
18213        _: &actions::FoldFunctionBodies,
18214        window: &mut Window,
18215        cx: &mut Context<Self>,
18216    ) {
18217        let snapshot = self.buffer.read(cx).snapshot(cx);
18218
18219        let ranges = snapshot
18220            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18221            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18222            .collect::<Vec<_>>();
18223
18224        let creases = ranges
18225            .into_iter()
18226            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18227            .collect();
18228
18229        self.fold_creases(creases, true, window, cx);
18230    }
18231
18232    pub fn fold_recursive(
18233        &mut self,
18234        _: &actions::FoldRecursive,
18235        window: &mut Window,
18236        cx: &mut Context<Self>,
18237    ) {
18238        let mut to_fold = Vec::new();
18239        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18240        let selections = self.selections.all_adjusted(&display_map);
18241
18242        for selection in selections {
18243            let range = selection.range().sorted();
18244            let buffer_start_row = range.start.row;
18245
18246            if range.start.row != range.end.row {
18247                let mut found = false;
18248                for row in range.start.row..=range.end.row {
18249                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18250                        found = true;
18251                        to_fold.push(crease);
18252                    }
18253                }
18254                if found {
18255                    continue;
18256                }
18257            }
18258
18259            for row in (0..=range.start.row).rev() {
18260                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18261                    if crease.range().end.row >= buffer_start_row {
18262                        to_fold.push(crease);
18263                    } else {
18264                        break;
18265                    }
18266                }
18267            }
18268        }
18269
18270        self.fold_creases(to_fold, true, window, cx);
18271    }
18272
18273    pub fn fold_at(
18274        &mut self,
18275        buffer_row: MultiBufferRow,
18276        window: &mut Window,
18277        cx: &mut Context<Self>,
18278    ) {
18279        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18280
18281        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18282            let autoscroll = self
18283                .selections
18284                .all::<Point>(&display_map)
18285                .iter()
18286                .any(|selection| crease.range().overlaps(&selection.range()));
18287
18288            self.fold_creases(vec![crease], autoscroll, window, cx);
18289        }
18290    }
18291
18292    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18293        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18294            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18295            let buffer = display_map.buffer_snapshot();
18296            let selections = self.selections.all::<Point>(&display_map);
18297            let ranges = selections
18298                .iter()
18299                .map(|s| {
18300                    let range = s.display_range(&display_map).sorted();
18301                    let mut start = range.start.to_point(&display_map);
18302                    let mut end = range.end.to_point(&display_map);
18303                    start.column = 0;
18304                    end.column = buffer.line_len(MultiBufferRow(end.row));
18305                    start..end
18306                })
18307                .collect::<Vec<_>>();
18308
18309            self.unfold_ranges(&ranges, true, true, cx);
18310        } else {
18311            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18312            let buffer_ids = self
18313                .selections
18314                .disjoint_anchor_ranges()
18315                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18316                .collect::<HashSet<_>>();
18317            for buffer_id in buffer_ids {
18318                self.unfold_buffer(buffer_id, cx);
18319            }
18320        }
18321    }
18322
18323    pub fn unfold_recursive(
18324        &mut self,
18325        _: &UnfoldRecursive,
18326        _window: &mut Window,
18327        cx: &mut Context<Self>,
18328    ) {
18329        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18330        let selections = self.selections.all::<Point>(&display_map);
18331        let ranges = selections
18332            .iter()
18333            .map(|s| {
18334                let mut range = s.display_range(&display_map).sorted();
18335                *range.start.column_mut() = 0;
18336                *range.end.column_mut() = display_map.line_len(range.end.row());
18337                let start = range.start.to_point(&display_map);
18338                let end = range.end.to_point(&display_map);
18339                start..end
18340            })
18341            .collect::<Vec<_>>();
18342
18343        self.unfold_ranges(&ranges, true, true, cx);
18344    }
18345
18346    pub fn unfold_at(
18347        &mut self,
18348        buffer_row: MultiBufferRow,
18349        _window: &mut Window,
18350        cx: &mut Context<Self>,
18351    ) {
18352        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18353
18354        let intersection_range = Point::new(buffer_row.0, 0)
18355            ..Point::new(
18356                buffer_row.0,
18357                display_map.buffer_snapshot().line_len(buffer_row),
18358            );
18359
18360        let autoscroll = self
18361            .selections
18362            .all::<Point>(&display_map)
18363            .iter()
18364            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18365
18366        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18367    }
18368
18369    pub fn unfold_all(
18370        &mut self,
18371        _: &actions::UnfoldAll,
18372        _window: &mut Window,
18373        cx: &mut Context<Self>,
18374    ) {
18375        if self.buffer.read(cx).is_singleton() {
18376            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18377            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18378        } else {
18379            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18380                editor
18381                    .update(cx, |editor, cx| {
18382                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18383                            editor.unfold_buffer(buffer_id, cx);
18384                        }
18385                    })
18386                    .ok();
18387            });
18388        }
18389    }
18390
18391    pub fn fold_selected_ranges(
18392        &mut self,
18393        _: &FoldSelectedRanges,
18394        window: &mut Window,
18395        cx: &mut Context<Self>,
18396    ) {
18397        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18398        let selections = self.selections.all_adjusted(&display_map);
18399        let ranges = selections
18400            .into_iter()
18401            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18402            .collect::<Vec<_>>();
18403        self.fold_creases(ranges, true, window, cx);
18404    }
18405
18406    pub fn fold_ranges<T: ToOffset + Clone>(
18407        &mut self,
18408        ranges: Vec<Range<T>>,
18409        auto_scroll: bool,
18410        window: &mut Window,
18411        cx: &mut Context<Self>,
18412    ) {
18413        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18414        let ranges = ranges
18415            .into_iter()
18416            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18417            .collect::<Vec<_>>();
18418        self.fold_creases(ranges, auto_scroll, window, cx);
18419    }
18420
18421    pub fn fold_creases<T: ToOffset + Clone>(
18422        &mut self,
18423        creases: Vec<Crease<T>>,
18424        auto_scroll: bool,
18425        _window: &mut Window,
18426        cx: &mut Context<Self>,
18427    ) {
18428        if creases.is_empty() {
18429            return;
18430        }
18431
18432        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18433
18434        if auto_scroll {
18435            self.request_autoscroll(Autoscroll::fit(), cx);
18436        }
18437
18438        cx.notify();
18439
18440        self.scrollbar_marker_state.dirty = true;
18441        self.folds_did_change(cx);
18442    }
18443
18444    /// Removes any folds whose ranges intersect any of the given ranges.
18445    pub fn unfold_ranges<T: ToOffset + Clone>(
18446        &mut self,
18447        ranges: &[Range<T>],
18448        inclusive: bool,
18449        auto_scroll: bool,
18450        cx: &mut Context<Self>,
18451    ) {
18452        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18453            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18454        });
18455        self.folds_did_change(cx);
18456    }
18457
18458    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18459        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18460            return;
18461        }
18462        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18463        self.display_map.update(cx, |display_map, cx| {
18464            display_map.fold_buffers([buffer_id], cx)
18465        });
18466        cx.emit(EditorEvent::BufferFoldToggled {
18467            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18468            folded: true,
18469        });
18470        cx.notify();
18471    }
18472
18473    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18474        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18475            return;
18476        }
18477        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18478        self.display_map.update(cx, |display_map, cx| {
18479            display_map.unfold_buffers([buffer_id], cx);
18480        });
18481        cx.emit(EditorEvent::BufferFoldToggled {
18482            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18483            folded: false,
18484        });
18485        cx.notify();
18486    }
18487
18488    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18489        self.display_map.read(cx).is_buffer_folded(buffer)
18490    }
18491
18492    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18493        self.display_map.read(cx).folded_buffers()
18494    }
18495
18496    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18497        self.display_map.update(cx, |display_map, cx| {
18498            display_map.disable_header_for_buffer(buffer_id, cx);
18499        });
18500        cx.notify();
18501    }
18502
18503    /// Removes any folds with the given ranges.
18504    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18505        &mut self,
18506        ranges: &[Range<T>],
18507        type_id: TypeId,
18508        auto_scroll: bool,
18509        cx: &mut Context<Self>,
18510    ) {
18511        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18512            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18513        });
18514        self.folds_did_change(cx);
18515    }
18516
18517    fn remove_folds_with<T: ToOffset + Clone>(
18518        &mut self,
18519        ranges: &[Range<T>],
18520        auto_scroll: bool,
18521        cx: &mut Context<Self>,
18522        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18523    ) {
18524        if ranges.is_empty() {
18525            return;
18526        }
18527
18528        let mut buffers_affected = HashSet::default();
18529        let multi_buffer = self.buffer().read(cx);
18530        for range in ranges {
18531            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18532                buffers_affected.insert(buffer.read(cx).remote_id());
18533            };
18534        }
18535
18536        self.display_map.update(cx, update);
18537
18538        if auto_scroll {
18539            self.request_autoscroll(Autoscroll::fit(), cx);
18540        }
18541
18542        cx.notify();
18543        self.scrollbar_marker_state.dirty = true;
18544        self.active_indent_guides_state.dirty = true;
18545    }
18546
18547    pub fn update_renderer_widths(
18548        &mut self,
18549        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18550        cx: &mut Context<Self>,
18551    ) -> bool {
18552        self.display_map
18553            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18554    }
18555
18556    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18557        self.display_map.read(cx).fold_placeholder.clone()
18558    }
18559
18560    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18561        self.buffer.update(cx, |buffer, cx| {
18562            buffer.set_all_diff_hunks_expanded(cx);
18563        });
18564    }
18565
18566    pub fn expand_all_diff_hunks(
18567        &mut self,
18568        _: &ExpandAllDiffHunks,
18569        _window: &mut Window,
18570        cx: &mut Context<Self>,
18571    ) {
18572        self.buffer.update(cx, |buffer, cx| {
18573            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18574        });
18575    }
18576
18577    pub fn collapse_all_diff_hunks(
18578        &mut self,
18579        _: &CollapseAllDiffHunks,
18580        _window: &mut Window,
18581        cx: &mut Context<Self>,
18582    ) {
18583        self.buffer.update(cx, |buffer, cx| {
18584            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18585        });
18586    }
18587
18588    pub fn toggle_selected_diff_hunks(
18589        &mut self,
18590        _: &ToggleSelectedDiffHunks,
18591        _window: &mut Window,
18592        cx: &mut Context<Self>,
18593    ) {
18594        let ranges: Vec<_> = self
18595            .selections
18596            .disjoint_anchors()
18597            .iter()
18598            .map(|s| s.range())
18599            .collect();
18600        self.toggle_diff_hunks_in_ranges(ranges, cx);
18601    }
18602
18603    pub fn diff_hunks_in_ranges<'a>(
18604        &'a self,
18605        ranges: &'a [Range<Anchor>],
18606        buffer: &'a MultiBufferSnapshot,
18607    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18608        ranges.iter().flat_map(move |range| {
18609            let end_excerpt_id = range.end.excerpt_id;
18610            let range = range.to_point(buffer);
18611            let mut peek_end = range.end;
18612            if range.end.row < buffer.max_row().0 {
18613                peek_end = Point::new(range.end.row + 1, 0);
18614            }
18615            buffer
18616                .diff_hunks_in_range(range.start..peek_end)
18617                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18618        })
18619    }
18620
18621    pub fn has_stageable_diff_hunks_in_ranges(
18622        &self,
18623        ranges: &[Range<Anchor>],
18624        snapshot: &MultiBufferSnapshot,
18625    ) -> bool {
18626        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18627        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18628    }
18629
18630    pub fn toggle_staged_selected_diff_hunks(
18631        &mut self,
18632        _: &::git::ToggleStaged,
18633        _: &mut Window,
18634        cx: &mut Context<Self>,
18635    ) {
18636        let snapshot = self.buffer.read(cx).snapshot(cx);
18637        let ranges: Vec<_> = self
18638            .selections
18639            .disjoint_anchors()
18640            .iter()
18641            .map(|s| s.range())
18642            .collect();
18643        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18644        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18645    }
18646
18647    pub fn set_render_diff_hunk_controls(
18648        &mut self,
18649        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18650        cx: &mut Context<Self>,
18651    ) {
18652        self.render_diff_hunk_controls = render_diff_hunk_controls;
18653        cx.notify();
18654    }
18655
18656    pub fn stage_and_next(
18657        &mut self,
18658        _: &::git::StageAndNext,
18659        window: &mut Window,
18660        cx: &mut Context<Self>,
18661    ) {
18662        self.do_stage_or_unstage_and_next(true, window, cx);
18663    }
18664
18665    pub fn unstage_and_next(
18666        &mut self,
18667        _: &::git::UnstageAndNext,
18668        window: &mut Window,
18669        cx: &mut Context<Self>,
18670    ) {
18671        self.do_stage_or_unstage_and_next(false, window, cx);
18672    }
18673
18674    pub fn stage_or_unstage_diff_hunks(
18675        &mut self,
18676        stage: bool,
18677        ranges: Vec<Range<Anchor>>,
18678        cx: &mut Context<Self>,
18679    ) {
18680        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18681        cx.spawn(async move |this, cx| {
18682            task.await?;
18683            this.update(cx, |this, cx| {
18684                let snapshot = this.buffer.read(cx).snapshot(cx);
18685                let chunk_by = this
18686                    .diff_hunks_in_ranges(&ranges, &snapshot)
18687                    .chunk_by(|hunk| hunk.buffer_id);
18688                for (buffer_id, hunks) in &chunk_by {
18689                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18690                }
18691            })
18692        })
18693        .detach_and_log_err(cx);
18694    }
18695
18696    fn save_buffers_for_ranges_if_needed(
18697        &mut self,
18698        ranges: &[Range<Anchor>],
18699        cx: &mut Context<Editor>,
18700    ) -> Task<Result<()>> {
18701        let multibuffer = self.buffer.read(cx);
18702        let snapshot = multibuffer.read(cx);
18703        let buffer_ids: HashSet<_> = ranges
18704            .iter()
18705            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18706            .collect();
18707        drop(snapshot);
18708
18709        let mut buffers = HashSet::default();
18710        for buffer_id in buffer_ids {
18711            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18712                let buffer = buffer_entity.read(cx);
18713                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18714                {
18715                    buffers.insert(buffer_entity);
18716                }
18717            }
18718        }
18719
18720        if let Some(project) = &self.project {
18721            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18722        } else {
18723            Task::ready(Ok(()))
18724        }
18725    }
18726
18727    fn do_stage_or_unstage_and_next(
18728        &mut self,
18729        stage: bool,
18730        window: &mut Window,
18731        cx: &mut Context<Self>,
18732    ) {
18733        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18734
18735        if ranges.iter().any(|range| range.start != range.end) {
18736            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18737            return;
18738        }
18739
18740        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18741        let snapshot = self.snapshot(window, cx);
18742        let position = self
18743            .selections
18744            .newest::<Point>(&snapshot.display_snapshot)
18745            .head();
18746        let mut row = snapshot
18747            .buffer_snapshot()
18748            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18749            .find(|hunk| hunk.row_range.start.0 > position.row)
18750            .map(|hunk| hunk.row_range.start);
18751
18752        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18753        // Outside of the project diff editor, wrap around to the beginning.
18754        if !all_diff_hunks_expanded {
18755            row = row.or_else(|| {
18756                snapshot
18757                    .buffer_snapshot()
18758                    .diff_hunks_in_range(Point::zero()..position)
18759                    .find(|hunk| hunk.row_range.end.0 < position.row)
18760                    .map(|hunk| hunk.row_range.start)
18761            });
18762        }
18763
18764        if let Some(row) = row {
18765            let destination = Point::new(row.0, 0);
18766            let autoscroll = Autoscroll::center();
18767
18768            self.unfold_ranges(&[destination..destination], false, false, cx);
18769            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18770                s.select_ranges([destination..destination]);
18771            });
18772        }
18773    }
18774
18775    fn do_stage_or_unstage(
18776        &self,
18777        stage: bool,
18778        buffer_id: BufferId,
18779        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18780        cx: &mut App,
18781    ) -> Option<()> {
18782        let project = self.project()?;
18783        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18784        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18785        let buffer_snapshot = buffer.read(cx).snapshot();
18786        let file_exists = buffer_snapshot
18787            .file()
18788            .is_some_and(|file| file.disk_state().exists());
18789        diff.update(cx, |diff, cx| {
18790            diff.stage_or_unstage_hunks(
18791                stage,
18792                &hunks
18793                    .map(|hunk| buffer_diff::DiffHunk {
18794                        buffer_range: hunk.buffer_range,
18795                        diff_base_byte_range: hunk.diff_base_byte_range,
18796                        secondary_status: hunk.secondary_status,
18797                        range: Point::zero()..Point::zero(), // unused
18798                    })
18799                    .collect::<Vec<_>>(),
18800                &buffer_snapshot,
18801                file_exists,
18802                cx,
18803            )
18804        });
18805        None
18806    }
18807
18808    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18809        let ranges: Vec<_> = self
18810            .selections
18811            .disjoint_anchors()
18812            .iter()
18813            .map(|s| s.range())
18814            .collect();
18815        self.buffer
18816            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18817    }
18818
18819    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18820        self.buffer.update(cx, |buffer, cx| {
18821            let ranges = vec![Anchor::min()..Anchor::max()];
18822            if !buffer.all_diff_hunks_expanded()
18823                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18824            {
18825                buffer.collapse_diff_hunks(ranges, cx);
18826                true
18827            } else {
18828                false
18829            }
18830        })
18831    }
18832
18833    fn toggle_diff_hunks_in_ranges(
18834        &mut self,
18835        ranges: Vec<Range<Anchor>>,
18836        cx: &mut Context<Editor>,
18837    ) {
18838        self.buffer.update(cx, |buffer, cx| {
18839            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18840            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18841        })
18842    }
18843
18844    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18845        self.buffer.update(cx, |buffer, cx| {
18846            let snapshot = buffer.snapshot(cx);
18847            let excerpt_id = range.end.excerpt_id;
18848            let point_range = range.to_point(&snapshot);
18849            let expand = !buffer.single_hunk_is_expanded(range, cx);
18850            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18851        })
18852    }
18853
18854    pub(crate) fn apply_all_diff_hunks(
18855        &mut self,
18856        _: &ApplyAllDiffHunks,
18857        window: &mut Window,
18858        cx: &mut Context<Self>,
18859    ) {
18860        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18861
18862        let buffers = self.buffer.read(cx).all_buffers();
18863        for branch_buffer in buffers {
18864            branch_buffer.update(cx, |branch_buffer, cx| {
18865                branch_buffer.merge_into_base(Vec::new(), cx);
18866            });
18867        }
18868
18869        if let Some(project) = self.project.clone() {
18870            self.save(
18871                SaveOptions {
18872                    format: true,
18873                    autosave: false,
18874                },
18875                project,
18876                window,
18877                cx,
18878            )
18879            .detach_and_log_err(cx);
18880        }
18881    }
18882
18883    pub(crate) fn apply_selected_diff_hunks(
18884        &mut self,
18885        _: &ApplyDiffHunk,
18886        window: &mut Window,
18887        cx: &mut Context<Self>,
18888    ) {
18889        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18890        let snapshot = self.snapshot(window, cx);
18891        let hunks = snapshot.hunks_for_ranges(
18892            self.selections
18893                .all(&snapshot.display_snapshot)
18894                .into_iter()
18895                .map(|selection| selection.range()),
18896        );
18897        let mut ranges_by_buffer = HashMap::default();
18898        self.transact(window, cx, |editor, _window, cx| {
18899            for hunk in hunks {
18900                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18901                    ranges_by_buffer
18902                        .entry(buffer.clone())
18903                        .or_insert_with(Vec::new)
18904                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18905                }
18906            }
18907
18908            for (buffer, ranges) in ranges_by_buffer {
18909                buffer.update(cx, |buffer, cx| {
18910                    buffer.merge_into_base(ranges, cx);
18911                });
18912            }
18913        });
18914
18915        if let Some(project) = self.project.clone() {
18916            self.save(
18917                SaveOptions {
18918                    format: true,
18919                    autosave: false,
18920                },
18921                project,
18922                window,
18923                cx,
18924            )
18925            .detach_and_log_err(cx);
18926        }
18927    }
18928
18929    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18930        if hovered != self.gutter_hovered {
18931            self.gutter_hovered = hovered;
18932            cx.notify();
18933        }
18934    }
18935
18936    pub fn insert_blocks(
18937        &mut self,
18938        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18939        autoscroll: Option<Autoscroll>,
18940        cx: &mut Context<Self>,
18941    ) -> Vec<CustomBlockId> {
18942        let blocks = self
18943            .display_map
18944            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18945        if let Some(autoscroll) = autoscroll {
18946            self.request_autoscroll(autoscroll, cx);
18947        }
18948        cx.notify();
18949        blocks
18950    }
18951
18952    pub fn resize_blocks(
18953        &mut self,
18954        heights: HashMap<CustomBlockId, u32>,
18955        autoscroll: Option<Autoscroll>,
18956        cx: &mut Context<Self>,
18957    ) {
18958        self.display_map
18959            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18960        if let Some(autoscroll) = autoscroll {
18961            self.request_autoscroll(autoscroll, cx);
18962        }
18963        cx.notify();
18964    }
18965
18966    pub fn replace_blocks(
18967        &mut self,
18968        renderers: HashMap<CustomBlockId, RenderBlock>,
18969        autoscroll: Option<Autoscroll>,
18970        cx: &mut Context<Self>,
18971    ) {
18972        self.display_map
18973            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18974        if let Some(autoscroll) = autoscroll {
18975            self.request_autoscroll(autoscroll, cx);
18976        }
18977        cx.notify();
18978    }
18979
18980    pub fn remove_blocks(
18981        &mut self,
18982        block_ids: HashSet<CustomBlockId>,
18983        autoscroll: Option<Autoscroll>,
18984        cx: &mut Context<Self>,
18985    ) {
18986        self.display_map.update(cx, |display_map, cx| {
18987            display_map.remove_blocks(block_ids, cx)
18988        });
18989        if let Some(autoscroll) = autoscroll {
18990            self.request_autoscroll(autoscroll, cx);
18991        }
18992        cx.notify();
18993    }
18994
18995    pub fn row_for_block(
18996        &self,
18997        block_id: CustomBlockId,
18998        cx: &mut Context<Self>,
18999    ) -> Option<DisplayRow> {
19000        self.display_map
19001            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19002    }
19003
19004    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19005        self.focused_block = Some(focused_block);
19006    }
19007
19008    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19009        self.focused_block.take()
19010    }
19011
19012    pub fn insert_creases(
19013        &mut self,
19014        creases: impl IntoIterator<Item = Crease<Anchor>>,
19015        cx: &mut Context<Self>,
19016    ) -> Vec<CreaseId> {
19017        self.display_map
19018            .update(cx, |map, cx| map.insert_creases(creases, cx))
19019    }
19020
19021    pub fn remove_creases(
19022        &mut self,
19023        ids: impl IntoIterator<Item = CreaseId>,
19024        cx: &mut Context<Self>,
19025    ) -> Vec<(CreaseId, Range<Anchor>)> {
19026        self.display_map
19027            .update(cx, |map, cx| map.remove_creases(ids, cx))
19028    }
19029
19030    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19031        self.display_map
19032            .update(cx, |map, cx| map.snapshot(cx))
19033            .longest_row()
19034    }
19035
19036    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19037        self.display_map
19038            .update(cx, |map, cx| map.snapshot(cx))
19039            .max_point()
19040    }
19041
19042    pub fn text(&self, cx: &App) -> String {
19043        self.buffer.read(cx).read(cx).text()
19044    }
19045
19046    pub fn is_empty(&self, cx: &App) -> bool {
19047        self.buffer.read(cx).read(cx).is_empty()
19048    }
19049
19050    pub fn text_option(&self, cx: &App) -> Option<String> {
19051        let text = self.text(cx);
19052        let text = text.trim();
19053
19054        if text.is_empty() {
19055            return None;
19056        }
19057
19058        Some(text.to_string())
19059    }
19060
19061    pub fn set_text(
19062        &mut self,
19063        text: impl Into<Arc<str>>,
19064        window: &mut Window,
19065        cx: &mut Context<Self>,
19066    ) {
19067        self.transact(window, cx, |this, _, cx| {
19068            this.buffer
19069                .read(cx)
19070                .as_singleton()
19071                .expect("you can only call set_text on editors for singleton buffers")
19072                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19073        });
19074    }
19075
19076    pub fn display_text(&self, cx: &mut App) -> String {
19077        self.display_map
19078            .update(cx, |map, cx| map.snapshot(cx))
19079            .text()
19080    }
19081
19082    fn create_minimap(
19083        &self,
19084        minimap_settings: MinimapSettings,
19085        window: &mut Window,
19086        cx: &mut Context<Self>,
19087    ) -> Option<Entity<Self>> {
19088        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19089            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19090    }
19091
19092    fn initialize_new_minimap(
19093        &self,
19094        minimap_settings: MinimapSettings,
19095        window: &mut Window,
19096        cx: &mut Context<Self>,
19097    ) -> Entity<Self> {
19098        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19099
19100        let mut minimap = Editor::new_internal(
19101            EditorMode::Minimap {
19102                parent: cx.weak_entity(),
19103            },
19104            self.buffer.clone(),
19105            None,
19106            Some(self.display_map.clone()),
19107            window,
19108            cx,
19109        );
19110        minimap.scroll_manager.clone_state(&self.scroll_manager);
19111        minimap.set_text_style_refinement(TextStyleRefinement {
19112            font_size: Some(MINIMAP_FONT_SIZE),
19113            font_weight: Some(MINIMAP_FONT_WEIGHT),
19114            ..Default::default()
19115        });
19116        minimap.update_minimap_configuration(minimap_settings, cx);
19117        cx.new(|_| minimap)
19118    }
19119
19120    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19121        let current_line_highlight = minimap_settings
19122            .current_line_highlight
19123            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19124        self.set_current_line_highlight(Some(current_line_highlight));
19125    }
19126
19127    pub fn minimap(&self) -> Option<&Entity<Self>> {
19128        self.minimap
19129            .as_ref()
19130            .filter(|_| self.minimap_visibility.visible())
19131    }
19132
19133    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19134        let mut wrap_guides = smallvec![];
19135
19136        if self.show_wrap_guides == Some(false) {
19137            return wrap_guides;
19138        }
19139
19140        let settings = self.buffer.read(cx).language_settings(cx);
19141        if settings.show_wrap_guides {
19142            match self.soft_wrap_mode(cx) {
19143                SoftWrap::Column(soft_wrap) => {
19144                    wrap_guides.push((soft_wrap as usize, true));
19145                }
19146                SoftWrap::Bounded(soft_wrap) => {
19147                    wrap_guides.push((soft_wrap as usize, true));
19148                }
19149                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19150            }
19151            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19152        }
19153
19154        wrap_guides
19155    }
19156
19157    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19158        let settings = self.buffer.read(cx).language_settings(cx);
19159        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19160        match mode {
19161            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19162                SoftWrap::None
19163            }
19164            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19165            language_settings::SoftWrap::PreferredLineLength => {
19166                SoftWrap::Column(settings.preferred_line_length)
19167            }
19168            language_settings::SoftWrap::Bounded => {
19169                SoftWrap::Bounded(settings.preferred_line_length)
19170            }
19171        }
19172    }
19173
19174    pub fn set_soft_wrap_mode(
19175        &mut self,
19176        mode: language_settings::SoftWrap,
19177
19178        cx: &mut Context<Self>,
19179    ) {
19180        self.soft_wrap_mode_override = Some(mode);
19181        cx.notify();
19182    }
19183
19184    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19185        self.hard_wrap = hard_wrap;
19186        cx.notify();
19187    }
19188
19189    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19190        self.text_style_refinement = Some(style);
19191    }
19192
19193    /// called by the Element so we know what style we were most recently rendered with.
19194    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19195        // We intentionally do not inform the display map about the minimap style
19196        // so that wrapping is not recalculated and stays consistent for the editor
19197        // and its linked minimap.
19198        if !self.mode.is_minimap() {
19199            let font = style.text.font();
19200            let font_size = style.text.font_size.to_pixels(window.rem_size());
19201            let display_map = self
19202                .placeholder_display_map
19203                .as_ref()
19204                .filter(|_| self.is_empty(cx))
19205                .unwrap_or(&self.display_map);
19206
19207            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19208        }
19209        self.style = Some(style);
19210    }
19211
19212    pub fn style(&self) -> Option<&EditorStyle> {
19213        self.style.as_ref()
19214    }
19215
19216    // Called by the element. This method is not designed to be called outside of the editor
19217    // element's layout code because it does not notify when rewrapping is computed synchronously.
19218    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19219        if self.is_empty(cx) {
19220            self.placeholder_display_map
19221                .as_ref()
19222                .map_or(false, |display_map| {
19223                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19224                })
19225        } else {
19226            self.display_map
19227                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19228        }
19229    }
19230
19231    pub fn set_soft_wrap(&mut self) {
19232        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19233    }
19234
19235    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19236        if self.soft_wrap_mode_override.is_some() {
19237            self.soft_wrap_mode_override.take();
19238        } else {
19239            let soft_wrap = match self.soft_wrap_mode(cx) {
19240                SoftWrap::GitDiff => return,
19241                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19242                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19243                    language_settings::SoftWrap::None
19244                }
19245            };
19246            self.soft_wrap_mode_override = Some(soft_wrap);
19247        }
19248        cx.notify();
19249    }
19250
19251    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19252        let Some(workspace) = self.workspace() else {
19253            return;
19254        };
19255        let fs = workspace.read(cx).app_state().fs.clone();
19256        let current_show = TabBarSettings::get_global(cx).show;
19257        update_settings_file(fs, cx, move |setting, _| {
19258            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19259        });
19260    }
19261
19262    pub fn toggle_indent_guides(
19263        &mut self,
19264        _: &ToggleIndentGuides,
19265        _: &mut Window,
19266        cx: &mut Context<Self>,
19267    ) {
19268        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19269            self.buffer
19270                .read(cx)
19271                .language_settings(cx)
19272                .indent_guides
19273                .enabled
19274        });
19275        self.show_indent_guides = Some(!currently_enabled);
19276        cx.notify();
19277    }
19278
19279    fn should_show_indent_guides(&self) -> Option<bool> {
19280        self.show_indent_guides
19281    }
19282
19283    pub fn toggle_line_numbers(
19284        &mut self,
19285        _: &ToggleLineNumbers,
19286        _: &mut Window,
19287        cx: &mut Context<Self>,
19288    ) {
19289        let mut editor_settings = EditorSettings::get_global(cx).clone();
19290        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19291        EditorSettings::override_global(editor_settings, cx);
19292    }
19293
19294    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19295        if let Some(show_line_numbers) = self.show_line_numbers {
19296            return show_line_numbers;
19297        }
19298        EditorSettings::get_global(cx).gutter.line_numbers
19299    }
19300
19301    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19302        self.use_relative_line_numbers
19303            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19304    }
19305
19306    pub fn toggle_relative_line_numbers(
19307        &mut self,
19308        _: &ToggleRelativeLineNumbers,
19309        _: &mut Window,
19310        cx: &mut Context<Self>,
19311    ) {
19312        let is_relative = self.should_use_relative_line_numbers(cx);
19313        self.set_relative_line_number(Some(!is_relative), cx)
19314    }
19315
19316    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19317        self.use_relative_line_numbers = is_relative;
19318        cx.notify();
19319    }
19320
19321    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19322        self.show_gutter = show_gutter;
19323        cx.notify();
19324    }
19325
19326    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19327        self.show_scrollbars = ScrollbarAxes {
19328            horizontal: show,
19329            vertical: show,
19330        };
19331        cx.notify();
19332    }
19333
19334    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19335        self.show_scrollbars.vertical = show;
19336        cx.notify();
19337    }
19338
19339    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19340        self.show_scrollbars.horizontal = show;
19341        cx.notify();
19342    }
19343
19344    pub fn set_minimap_visibility(
19345        &mut self,
19346        minimap_visibility: MinimapVisibility,
19347        window: &mut Window,
19348        cx: &mut Context<Self>,
19349    ) {
19350        if self.minimap_visibility != minimap_visibility {
19351            if minimap_visibility.visible() && self.minimap.is_none() {
19352                let minimap_settings = EditorSettings::get_global(cx).minimap;
19353                self.minimap =
19354                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19355            }
19356            self.minimap_visibility = minimap_visibility;
19357            cx.notify();
19358        }
19359    }
19360
19361    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19362        self.set_show_scrollbars(false, cx);
19363        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19364    }
19365
19366    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19367        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19368    }
19369
19370    /// Normally the text in full mode and auto height editors is padded on the
19371    /// left side by roughly half a character width for improved hit testing.
19372    ///
19373    /// Use this method to disable this for cases where this is not wanted (e.g.
19374    /// if you want to align the editor text with some other text above or below)
19375    /// or if you want to add this padding to single-line editors.
19376    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19377        self.offset_content = offset_content;
19378        cx.notify();
19379    }
19380
19381    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19382        self.show_line_numbers = Some(show_line_numbers);
19383        cx.notify();
19384    }
19385
19386    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19387        self.disable_expand_excerpt_buttons = true;
19388        cx.notify();
19389    }
19390
19391    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19392        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19393        cx.notify();
19394    }
19395
19396    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19397        self.show_code_actions = Some(show_code_actions);
19398        cx.notify();
19399    }
19400
19401    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19402        self.show_runnables = Some(show_runnables);
19403        cx.notify();
19404    }
19405
19406    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19407        self.show_breakpoints = Some(show_breakpoints);
19408        cx.notify();
19409    }
19410
19411    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19412        if self.display_map.read(cx).masked != masked {
19413            self.display_map.update(cx, |map, _| map.masked = masked);
19414        }
19415        cx.notify()
19416    }
19417
19418    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19419        self.show_wrap_guides = Some(show_wrap_guides);
19420        cx.notify();
19421    }
19422
19423    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19424        self.show_indent_guides = Some(show_indent_guides);
19425        cx.notify();
19426    }
19427
19428    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19429        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19430            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19431                && let Some(dir) = file.abs_path(cx).parent()
19432            {
19433                return Some(dir.to_owned());
19434            }
19435        }
19436
19437        None
19438    }
19439
19440    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19441        self.active_excerpt(cx)?
19442            .1
19443            .read(cx)
19444            .file()
19445            .and_then(|f| f.as_local())
19446    }
19447
19448    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19449        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19450            let buffer = buffer.read(cx);
19451            if let Some(project_path) = buffer.project_path(cx) {
19452                let project = self.project()?.read(cx);
19453                project.absolute_path(&project_path, cx)
19454            } else {
19455                buffer
19456                    .file()
19457                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19458            }
19459        })
19460    }
19461
19462    pub fn reveal_in_finder(
19463        &mut self,
19464        _: &RevealInFileManager,
19465        _window: &mut Window,
19466        cx: &mut Context<Self>,
19467    ) {
19468        if let Some(target) = self.target_file(cx) {
19469            cx.reveal_path(&target.abs_path(cx));
19470        }
19471    }
19472
19473    pub fn copy_path(
19474        &mut self,
19475        _: &zed_actions::workspace::CopyPath,
19476        _window: &mut Window,
19477        cx: &mut Context<Self>,
19478    ) {
19479        if let Some(path) = self.target_file_abs_path(cx)
19480            && let Some(path) = path.to_str()
19481        {
19482            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19483        } else {
19484            cx.propagate();
19485        }
19486    }
19487
19488    pub fn copy_relative_path(
19489        &mut self,
19490        _: &zed_actions::workspace::CopyRelativePath,
19491        _window: &mut Window,
19492        cx: &mut Context<Self>,
19493    ) {
19494        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19495            let project = self.project()?.read(cx);
19496            let path = buffer.read(cx).file()?.path();
19497            let path = path.display(project.path_style(cx));
19498            Some(path)
19499        }) {
19500            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19501        } else {
19502            cx.propagate();
19503        }
19504    }
19505
19506    /// Returns the project path for the editor's buffer, if any buffer is
19507    /// opened in the editor.
19508    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19509        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19510            buffer.read(cx).project_path(cx)
19511        } else {
19512            None
19513        }
19514    }
19515
19516    // Returns true if the editor handled a go-to-line request
19517    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19518        maybe!({
19519            let breakpoint_store = self.breakpoint_store.as_ref()?;
19520
19521            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19522            else {
19523                self.clear_row_highlights::<ActiveDebugLine>();
19524                return None;
19525            };
19526
19527            let position = active_stack_frame.position;
19528            let buffer_id = position.buffer_id?;
19529            let snapshot = self
19530                .project
19531                .as_ref()?
19532                .read(cx)
19533                .buffer_for_id(buffer_id, cx)?
19534                .read(cx)
19535                .snapshot();
19536
19537            let mut handled = false;
19538            for (id, ExcerptRange { context, .. }) in
19539                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19540            {
19541                if context.start.cmp(&position, &snapshot).is_ge()
19542                    || context.end.cmp(&position, &snapshot).is_lt()
19543                {
19544                    continue;
19545                }
19546                let snapshot = self.buffer.read(cx).snapshot(cx);
19547                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19548
19549                handled = true;
19550                self.clear_row_highlights::<ActiveDebugLine>();
19551
19552                self.go_to_line::<ActiveDebugLine>(
19553                    multibuffer_anchor,
19554                    Some(cx.theme().colors().editor_debugger_active_line_background),
19555                    window,
19556                    cx,
19557                );
19558
19559                cx.notify();
19560            }
19561
19562            handled.then_some(())
19563        })
19564        .is_some()
19565    }
19566
19567    pub fn copy_file_name_without_extension(
19568        &mut self,
19569        _: &CopyFileNameWithoutExtension,
19570        _: &mut Window,
19571        cx: &mut Context<Self>,
19572    ) {
19573        if let Some(file) = self.target_file(cx)
19574            && let Some(file_stem) = file.path().file_stem()
19575        {
19576            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19577        }
19578    }
19579
19580    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19581        if let Some(file) = self.target_file(cx)
19582            && let Some(name) = file.path().file_name()
19583        {
19584            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19585        }
19586    }
19587
19588    pub fn toggle_git_blame(
19589        &mut self,
19590        _: &::git::Blame,
19591        window: &mut Window,
19592        cx: &mut Context<Self>,
19593    ) {
19594        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19595
19596        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19597            self.start_git_blame(true, window, cx);
19598        }
19599
19600        cx.notify();
19601    }
19602
19603    pub fn toggle_git_blame_inline(
19604        &mut self,
19605        _: &ToggleGitBlameInline,
19606        window: &mut Window,
19607        cx: &mut Context<Self>,
19608    ) {
19609        self.toggle_git_blame_inline_internal(true, window, cx);
19610        cx.notify();
19611    }
19612
19613    pub fn open_git_blame_commit(
19614        &mut self,
19615        _: &OpenGitBlameCommit,
19616        window: &mut Window,
19617        cx: &mut Context<Self>,
19618    ) {
19619        self.open_git_blame_commit_internal(window, cx);
19620    }
19621
19622    fn open_git_blame_commit_internal(
19623        &mut self,
19624        window: &mut Window,
19625        cx: &mut Context<Self>,
19626    ) -> Option<()> {
19627        let blame = self.blame.as_ref()?;
19628        let snapshot = self.snapshot(window, cx);
19629        let cursor = self
19630            .selections
19631            .newest::<Point>(&snapshot.display_snapshot)
19632            .head();
19633        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19634        let (_, blame_entry) = blame
19635            .update(cx, |blame, cx| {
19636                blame
19637                    .blame_for_rows(
19638                        &[RowInfo {
19639                            buffer_id: Some(buffer.remote_id()),
19640                            buffer_row: Some(point.row),
19641                            ..Default::default()
19642                        }],
19643                        cx,
19644                    )
19645                    .next()
19646            })
19647            .flatten()?;
19648        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19649        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19650        let workspace = self.workspace()?.downgrade();
19651        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19652        None
19653    }
19654
19655    pub fn git_blame_inline_enabled(&self) -> bool {
19656        self.git_blame_inline_enabled
19657    }
19658
19659    pub fn toggle_selection_menu(
19660        &mut self,
19661        _: &ToggleSelectionMenu,
19662        _: &mut Window,
19663        cx: &mut Context<Self>,
19664    ) {
19665        self.show_selection_menu = self
19666            .show_selection_menu
19667            .map(|show_selections_menu| !show_selections_menu)
19668            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19669
19670        cx.notify();
19671    }
19672
19673    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19674        self.show_selection_menu
19675            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19676    }
19677
19678    fn start_git_blame(
19679        &mut self,
19680        user_triggered: bool,
19681        window: &mut Window,
19682        cx: &mut Context<Self>,
19683    ) {
19684        if let Some(project) = self.project() {
19685            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19686                && buffer.read(cx).file().is_none()
19687            {
19688                return;
19689            }
19690
19691            let focused = self.focus_handle(cx).contains_focused(window, cx);
19692
19693            let project = project.clone();
19694            let blame = cx
19695                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19696            self.blame_subscription =
19697                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19698            self.blame = Some(blame);
19699        }
19700    }
19701
19702    fn toggle_git_blame_inline_internal(
19703        &mut self,
19704        user_triggered: bool,
19705        window: &mut Window,
19706        cx: &mut Context<Self>,
19707    ) {
19708        if self.git_blame_inline_enabled {
19709            self.git_blame_inline_enabled = false;
19710            self.show_git_blame_inline = false;
19711            self.show_git_blame_inline_delay_task.take();
19712        } else {
19713            self.git_blame_inline_enabled = true;
19714            self.start_git_blame_inline(user_triggered, window, cx);
19715        }
19716
19717        cx.notify();
19718    }
19719
19720    fn start_git_blame_inline(
19721        &mut self,
19722        user_triggered: bool,
19723        window: &mut Window,
19724        cx: &mut Context<Self>,
19725    ) {
19726        self.start_git_blame(user_triggered, window, cx);
19727
19728        if ProjectSettings::get_global(cx)
19729            .git
19730            .inline_blame_delay()
19731            .is_some()
19732        {
19733            self.start_inline_blame_timer(window, cx);
19734        } else {
19735            self.show_git_blame_inline = true
19736        }
19737    }
19738
19739    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19740        self.blame.as_ref()
19741    }
19742
19743    pub fn show_git_blame_gutter(&self) -> bool {
19744        self.show_git_blame_gutter
19745    }
19746
19747    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19748        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19749    }
19750
19751    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19752        self.show_git_blame_inline
19753            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19754            && !self.newest_selection_head_on_empty_line(cx)
19755            && self.has_blame_entries(cx)
19756    }
19757
19758    fn has_blame_entries(&self, cx: &App) -> bool {
19759        self.blame()
19760            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19761    }
19762
19763    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19764        let cursor_anchor = self.selections.newest_anchor().head();
19765
19766        let snapshot = self.buffer.read(cx).snapshot(cx);
19767        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19768
19769        snapshot.line_len(buffer_row) == 0
19770    }
19771
19772    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19773        let buffer_and_selection = maybe!({
19774            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19775            let selection_range = selection.range();
19776
19777            let multi_buffer = self.buffer().read(cx);
19778            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19779            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19780
19781            let (buffer, range, _) = if selection.reversed {
19782                buffer_ranges.first()
19783            } else {
19784                buffer_ranges.last()
19785            }?;
19786
19787            let selection = text::ToPoint::to_point(&range.start, buffer).row
19788                ..text::ToPoint::to_point(&range.end, buffer).row;
19789            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19790        });
19791
19792        let Some((buffer, selection)) = buffer_and_selection else {
19793            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19794        };
19795
19796        let Some(project) = self.project() else {
19797            return Task::ready(Err(anyhow!("editor does not have project")));
19798        };
19799
19800        project.update(cx, |project, cx| {
19801            project.get_permalink_to_line(&buffer, selection, cx)
19802        })
19803    }
19804
19805    pub fn copy_permalink_to_line(
19806        &mut self,
19807        _: &CopyPermalinkToLine,
19808        window: &mut Window,
19809        cx: &mut Context<Self>,
19810    ) {
19811        let permalink_task = self.get_permalink_to_line(cx);
19812        let workspace = self.workspace();
19813
19814        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19815            Ok(permalink) => {
19816                cx.update(|_, cx| {
19817                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19818                })
19819                .ok();
19820            }
19821            Err(err) => {
19822                let message = format!("Failed to copy permalink: {err}");
19823
19824                anyhow::Result::<()>::Err(err).log_err();
19825
19826                if let Some(workspace) = workspace {
19827                    workspace
19828                        .update_in(cx, |workspace, _, cx| {
19829                            struct CopyPermalinkToLine;
19830
19831                            workspace.show_toast(
19832                                Toast::new(
19833                                    NotificationId::unique::<CopyPermalinkToLine>(),
19834                                    message,
19835                                ),
19836                                cx,
19837                            )
19838                        })
19839                        .ok();
19840                }
19841            }
19842        })
19843        .detach();
19844    }
19845
19846    pub fn copy_file_location(
19847        &mut self,
19848        _: &CopyFileLocation,
19849        _: &mut Window,
19850        cx: &mut Context<Self>,
19851    ) {
19852        let selection = self
19853            .selections
19854            .newest::<Point>(&self.display_snapshot(cx))
19855            .start
19856            .row
19857            + 1;
19858        if let Some(file) = self.target_file(cx) {
19859            let path = file.path().display(file.path_style(cx));
19860            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19861        }
19862    }
19863
19864    pub fn open_permalink_to_line(
19865        &mut self,
19866        _: &OpenPermalinkToLine,
19867        window: &mut Window,
19868        cx: &mut Context<Self>,
19869    ) {
19870        let permalink_task = self.get_permalink_to_line(cx);
19871        let workspace = self.workspace();
19872
19873        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19874            Ok(permalink) => {
19875                cx.update(|_, cx| {
19876                    cx.open_url(permalink.as_ref());
19877                })
19878                .ok();
19879            }
19880            Err(err) => {
19881                let message = format!("Failed to open permalink: {err}");
19882
19883                anyhow::Result::<()>::Err(err).log_err();
19884
19885                if let Some(workspace) = workspace {
19886                    workspace
19887                        .update(cx, |workspace, cx| {
19888                            struct OpenPermalinkToLine;
19889
19890                            workspace.show_toast(
19891                                Toast::new(
19892                                    NotificationId::unique::<OpenPermalinkToLine>(),
19893                                    message,
19894                                ),
19895                                cx,
19896                            )
19897                        })
19898                        .ok();
19899                }
19900            }
19901        })
19902        .detach();
19903    }
19904
19905    pub fn insert_uuid_v4(
19906        &mut self,
19907        _: &InsertUuidV4,
19908        window: &mut Window,
19909        cx: &mut Context<Self>,
19910    ) {
19911        self.insert_uuid(UuidVersion::V4, window, cx);
19912    }
19913
19914    pub fn insert_uuid_v7(
19915        &mut self,
19916        _: &InsertUuidV7,
19917        window: &mut Window,
19918        cx: &mut Context<Self>,
19919    ) {
19920        self.insert_uuid(UuidVersion::V7, window, cx);
19921    }
19922
19923    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19924        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19925        self.transact(window, cx, |this, window, cx| {
19926            let edits = this
19927                .selections
19928                .all::<Point>(&this.display_snapshot(cx))
19929                .into_iter()
19930                .map(|selection| {
19931                    let uuid = match version {
19932                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19933                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19934                    };
19935
19936                    (selection.range(), uuid.to_string())
19937                });
19938            this.edit(edits, cx);
19939            this.refresh_edit_prediction(true, false, window, cx);
19940        });
19941    }
19942
19943    pub fn open_selections_in_multibuffer(
19944        &mut self,
19945        _: &OpenSelectionsInMultibuffer,
19946        window: &mut Window,
19947        cx: &mut Context<Self>,
19948    ) {
19949        let multibuffer = self.buffer.read(cx);
19950
19951        let Some(buffer) = multibuffer.as_singleton() else {
19952            return;
19953        };
19954
19955        let Some(workspace) = self.workspace() else {
19956            return;
19957        };
19958
19959        let title = multibuffer.title(cx).to_string();
19960
19961        let locations = self
19962            .selections
19963            .all_anchors(cx)
19964            .iter()
19965            .map(|selection| {
19966                (
19967                    buffer.clone(),
19968                    (selection.start.text_anchor..selection.end.text_anchor)
19969                        .to_point(buffer.read(cx)),
19970                )
19971            })
19972            .into_group_map();
19973
19974        cx.spawn_in(window, async move |_, cx| {
19975            workspace.update_in(cx, |workspace, window, cx| {
19976                Self::open_locations_in_multibuffer(
19977                    workspace,
19978                    locations,
19979                    format!("Selections for '{title}'"),
19980                    false,
19981                    MultibufferSelectionMode::All,
19982                    window,
19983                    cx,
19984                );
19985            })
19986        })
19987        .detach();
19988    }
19989
19990    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19991    /// last highlight added will be used.
19992    ///
19993    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19994    pub fn highlight_rows<T: 'static>(
19995        &mut self,
19996        range: Range<Anchor>,
19997        color: Hsla,
19998        options: RowHighlightOptions,
19999        cx: &mut Context<Self>,
20000    ) {
20001        let snapshot = self.buffer().read(cx).snapshot(cx);
20002        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20003        let ix = row_highlights.binary_search_by(|highlight| {
20004            Ordering::Equal
20005                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20006                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20007        });
20008
20009        if let Err(mut ix) = ix {
20010            let index = post_inc(&mut self.highlight_order);
20011
20012            // If this range intersects with the preceding highlight, then merge it with
20013            // the preceding highlight. Otherwise insert a new highlight.
20014            let mut merged = false;
20015            if ix > 0 {
20016                let prev_highlight = &mut row_highlights[ix - 1];
20017                if prev_highlight
20018                    .range
20019                    .end
20020                    .cmp(&range.start, &snapshot)
20021                    .is_ge()
20022                {
20023                    ix -= 1;
20024                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20025                        prev_highlight.range.end = range.end;
20026                    }
20027                    merged = true;
20028                    prev_highlight.index = index;
20029                    prev_highlight.color = color;
20030                    prev_highlight.options = options;
20031                }
20032            }
20033
20034            if !merged {
20035                row_highlights.insert(
20036                    ix,
20037                    RowHighlight {
20038                        range,
20039                        index,
20040                        color,
20041                        options,
20042                        type_id: TypeId::of::<T>(),
20043                    },
20044                );
20045            }
20046
20047            // If any of the following highlights intersect with this one, merge them.
20048            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20049                let highlight = &row_highlights[ix];
20050                if next_highlight
20051                    .range
20052                    .start
20053                    .cmp(&highlight.range.end, &snapshot)
20054                    .is_le()
20055                {
20056                    if next_highlight
20057                        .range
20058                        .end
20059                        .cmp(&highlight.range.end, &snapshot)
20060                        .is_gt()
20061                    {
20062                        row_highlights[ix].range.end = next_highlight.range.end;
20063                    }
20064                    row_highlights.remove(ix + 1);
20065                } else {
20066                    break;
20067                }
20068            }
20069        }
20070    }
20071
20072    /// Remove any highlighted row ranges of the given type that intersect the
20073    /// given ranges.
20074    pub fn remove_highlighted_rows<T: 'static>(
20075        &mut self,
20076        ranges_to_remove: Vec<Range<Anchor>>,
20077        cx: &mut Context<Self>,
20078    ) {
20079        let snapshot = self.buffer().read(cx).snapshot(cx);
20080        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20081        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20082        row_highlights.retain(|highlight| {
20083            while let Some(range_to_remove) = ranges_to_remove.peek() {
20084                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20085                    Ordering::Less | Ordering::Equal => {
20086                        ranges_to_remove.next();
20087                    }
20088                    Ordering::Greater => {
20089                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20090                            Ordering::Less | Ordering::Equal => {
20091                                return false;
20092                            }
20093                            Ordering::Greater => break,
20094                        }
20095                    }
20096                }
20097            }
20098
20099            true
20100        })
20101    }
20102
20103    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20104    pub fn clear_row_highlights<T: 'static>(&mut self) {
20105        self.highlighted_rows.remove(&TypeId::of::<T>());
20106    }
20107
20108    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20109    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20110        self.highlighted_rows
20111            .get(&TypeId::of::<T>())
20112            .map_or(&[] as &[_], |vec| vec.as_slice())
20113            .iter()
20114            .map(|highlight| (highlight.range.clone(), highlight.color))
20115    }
20116
20117    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20118    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20119    /// Allows to ignore certain kinds of highlights.
20120    pub fn highlighted_display_rows(
20121        &self,
20122        window: &mut Window,
20123        cx: &mut App,
20124    ) -> BTreeMap<DisplayRow, LineHighlight> {
20125        let snapshot = self.snapshot(window, cx);
20126        let mut used_highlight_orders = HashMap::default();
20127        self.highlighted_rows
20128            .iter()
20129            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20130            .fold(
20131                BTreeMap::<DisplayRow, LineHighlight>::new(),
20132                |mut unique_rows, highlight| {
20133                    let start = highlight.range.start.to_display_point(&snapshot);
20134                    let end = highlight.range.end.to_display_point(&snapshot);
20135                    let start_row = start.row().0;
20136                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20137                        && end.column() == 0
20138                    {
20139                        end.row().0.saturating_sub(1)
20140                    } else {
20141                        end.row().0
20142                    };
20143                    for row in start_row..=end_row {
20144                        let used_index =
20145                            used_highlight_orders.entry(row).or_insert(highlight.index);
20146                        if highlight.index >= *used_index {
20147                            *used_index = highlight.index;
20148                            unique_rows.insert(
20149                                DisplayRow(row),
20150                                LineHighlight {
20151                                    include_gutter: highlight.options.include_gutter,
20152                                    border: None,
20153                                    background: highlight.color.into(),
20154                                    type_id: Some(highlight.type_id),
20155                                },
20156                            );
20157                        }
20158                    }
20159                    unique_rows
20160                },
20161            )
20162    }
20163
20164    pub fn highlighted_display_row_for_autoscroll(
20165        &self,
20166        snapshot: &DisplaySnapshot,
20167    ) -> Option<DisplayRow> {
20168        self.highlighted_rows
20169            .values()
20170            .flat_map(|highlighted_rows| highlighted_rows.iter())
20171            .filter_map(|highlight| {
20172                if highlight.options.autoscroll {
20173                    Some(highlight.range.start.to_display_point(snapshot).row())
20174                } else {
20175                    None
20176                }
20177            })
20178            .min()
20179    }
20180
20181    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20182        self.highlight_background::<SearchWithinRange>(
20183            ranges,
20184            |colors| colors.colors().editor_document_highlight_read_background,
20185            cx,
20186        )
20187    }
20188
20189    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20190        self.breadcrumb_header = Some(new_header);
20191    }
20192
20193    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20194        self.clear_background_highlights::<SearchWithinRange>(cx);
20195    }
20196
20197    pub fn highlight_background<T: 'static>(
20198        &mut self,
20199        ranges: &[Range<Anchor>],
20200        color_fetcher: fn(&Theme) -> Hsla,
20201        cx: &mut Context<Self>,
20202    ) {
20203        self.background_highlights.insert(
20204            HighlightKey::Type(TypeId::of::<T>()),
20205            (color_fetcher, Arc::from(ranges)),
20206        );
20207        self.scrollbar_marker_state.dirty = true;
20208        cx.notify();
20209    }
20210
20211    pub fn highlight_background_key<T: 'static>(
20212        &mut self,
20213        key: usize,
20214        ranges: &[Range<Anchor>],
20215        color_fetcher: fn(&Theme) -> Hsla,
20216        cx: &mut Context<Self>,
20217    ) {
20218        self.background_highlights.insert(
20219            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20220            (color_fetcher, Arc::from(ranges)),
20221        );
20222        self.scrollbar_marker_state.dirty = true;
20223        cx.notify();
20224    }
20225
20226    pub fn clear_background_highlights<T: 'static>(
20227        &mut self,
20228        cx: &mut Context<Self>,
20229    ) -> Option<BackgroundHighlight> {
20230        let text_highlights = self
20231            .background_highlights
20232            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20233        if !text_highlights.1.is_empty() {
20234            self.scrollbar_marker_state.dirty = true;
20235            cx.notify();
20236        }
20237        Some(text_highlights)
20238    }
20239
20240    pub fn highlight_gutter<T: 'static>(
20241        &mut self,
20242        ranges: impl Into<Vec<Range<Anchor>>>,
20243        color_fetcher: fn(&App) -> Hsla,
20244        cx: &mut Context<Self>,
20245    ) {
20246        self.gutter_highlights
20247            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20248        cx.notify();
20249    }
20250
20251    pub fn clear_gutter_highlights<T: 'static>(
20252        &mut self,
20253        cx: &mut Context<Self>,
20254    ) -> Option<GutterHighlight> {
20255        cx.notify();
20256        self.gutter_highlights.remove(&TypeId::of::<T>())
20257    }
20258
20259    pub fn insert_gutter_highlight<T: 'static>(
20260        &mut self,
20261        range: Range<Anchor>,
20262        color_fetcher: fn(&App) -> Hsla,
20263        cx: &mut Context<Self>,
20264    ) {
20265        let snapshot = self.buffer().read(cx).snapshot(cx);
20266        let mut highlights = self
20267            .gutter_highlights
20268            .remove(&TypeId::of::<T>())
20269            .map(|(_, highlights)| highlights)
20270            .unwrap_or_default();
20271        let ix = highlights.binary_search_by(|highlight| {
20272            Ordering::Equal
20273                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20274                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20275        });
20276        if let Err(ix) = ix {
20277            highlights.insert(ix, range);
20278        }
20279        self.gutter_highlights
20280            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20281    }
20282
20283    pub fn remove_gutter_highlights<T: 'static>(
20284        &mut self,
20285        ranges_to_remove: Vec<Range<Anchor>>,
20286        cx: &mut Context<Self>,
20287    ) {
20288        let snapshot = self.buffer().read(cx).snapshot(cx);
20289        let Some((color_fetcher, mut gutter_highlights)) =
20290            self.gutter_highlights.remove(&TypeId::of::<T>())
20291        else {
20292            return;
20293        };
20294        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20295        gutter_highlights.retain(|highlight| {
20296            while let Some(range_to_remove) = ranges_to_remove.peek() {
20297                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20298                    Ordering::Less | Ordering::Equal => {
20299                        ranges_to_remove.next();
20300                    }
20301                    Ordering::Greater => {
20302                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20303                            Ordering::Less | Ordering::Equal => {
20304                                return false;
20305                            }
20306                            Ordering::Greater => break,
20307                        }
20308                    }
20309                }
20310            }
20311
20312            true
20313        });
20314        self.gutter_highlights
20315            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20316    }
20317
20318    #[cfg(feature = "test-support")]
20319    pub fn all_text_highlights(
20320        &self,
20321        window: &mut Window,
20322        cx: &mut Context<Self>,
20323    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20324        let snapshot = self.snapshot(window, cx);
20325        self.display_map.update(cx, |display_map, _| {
20326            display_map
20327                .all_text_highlights()
20328                .map(|highlight| {
20329                    let (style, ranges) = highlight.as_ref();
20330                    (
20331                        *style,
20332                        ranges
20333                            .iter()
20334                            .map(|range| range.clone().to_display_points(&snapshot))
20335                            .collect(),
20336                    )
20337                })
20338                .collect()
20339        })
20340    }
20341
20342    #[cfg(feature = "test-support")]
20343    pub fn all_text_background_highlights(
20344        &self,
20345        window: &mut Window,
20346        cx: &mut Context<Self>,
20347    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20348        let snapshot = self.snapshot(window, cx);
20349        let buffer = &snapshot.buffer_snapshot();
20350        let start = buffer.anchor_before(0);
20351        let end = buffer.anchor_after(buffer.len());
20352        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20353    }
20354
20355    #[cfg(any(test, feature = "test-support"))]
20356    pub fn sorted_background_highlights_in_range(
20357        &self,
20358        search_range: Range<Anchor>,
20359        display_snapshot: &DisplaySnapshot,
20360        theme: &Theme,
20361    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20362        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20363        res.sort_by(|a, b| {
20364            a.0.start
20365                .cmp(&b.0.start)
20366                .then_with(|| a.0.end.cmp(&b.0.end))
20367                .then_with(|| a.1.cmp(&b.1))
20368        });
20369        res
20370    }
20371
20372    #[cfg(feature = "test-support")]
20373    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20374        let snapshot = self.buffer().read(cx).snapshot(cx);
20375
20376        let highlights = self
20377            .background_highlights
20378            .get(&HighlightKey::Type(TypeId::of::<
20379                items::BufferSearchHighlights,
20380            >()));
20381
20382        if let Some((_color, ranges)) = highlights {
20383            ranges
20384                .iter()
20385                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20386                .collect_vec()
20387        } else {
20388            vec![]
20389        }
20390    }
20391
20392    fn document_highlights_for_position<'a>(
20393        &'a self,
20394        position: Anchor,
20395        buffer: &'a MultiBufferSnapshot,
20396    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20397        let read_highlights = self
20398            .background_highlights
20399            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20400            .map(|h| &h.1);
20401        let write_highlights = self
20402            .background_highlights
20403            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20404            .map(|h| &h.1);
20405        let left_position = position.bias_left(buffer);
20406        let right_position = position.bias_right(buffer);
20407        read_highlights
20408            .into_iter()
20409            .chain(write_highlights)
20410            .flat_map(move |ranges| {
20411                let start_ix = match ranges.binary_search_by(|probe| {
20412                    let cmp = probe.end.cmp(&left_position, buffer);
20413                    if cmp.is_ge() {
20414                        Ordering::Greater
20415                    } else {
20416                        Ordering::Less
20417                    }
20418                }) {
20419                    Ok(i) | Err(i) => i,
20420                };
20421
20422                ranges[start_ix..]
20423                    .iter()
20424                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20425            })
20426    }
20427
20428    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20429        self.background_highlights
20430            .get(&HighlightKey::Type(TypeId::of::<T>()))
20431            .is_some_and(|(_, highlights)| !highlights.is_empty())
20432    }
20433
20434    /// Returns all background highlights for a given range.
20435    ///
20436    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20437    pub fn background_highlights_in_range(
20438        &self,
20439        search_range: Range<Anchor>,
20440        display_snapshot: &DisplaySnapshot,
20441        theme: &Theme,
20442    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20443        let mut results = Vec::new();
20444        for (color_fetcher, ranges) in self.background_highlights.values() {
20445            let color = color_fetcher(theme);
20446            let start_ix = match ranges.binary_search_by(|probe| {
20447                let cmp = probe
20448                    .end
20449                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20450                if cmp.is_gt() {
20451                    Ordering::Greater
20452                } else {
20453                    Ordering::Less
20454                }
20455            }) {
20456                Ok(i) | Err(i) => i,
20457            };
20458            for range in &ranges[start_ix..] {
20459                if range
20460                    .start
20461                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20462                    .is_ge()
20463                {
20464                    break;
20465                }
20466
20467                let start = range.start.to_display_point(display_snapshot);
20468                let end = range.end.to_display_point(display_snapshot);
20469                results.push((start..end, color))
20470            }
20471        }
20472        results
20473    }
20474
20475    pub fn gutter_highlights_in_range(
20476        &self,
20477        search_range: Range<Anchor>,
20478        display_snapshot: &DisplaySnapshot,
20479        cx: &App,
20480    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20481        let mut results = Vec::new();
20482        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20483            let color = color_fetcher(cx);
20484            let start_ix = match ranges.binary_search_by(|probe| {
20485                let cmp = probe
20486                    .end
20487                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20488                if cmp.is_gt() {
20489                    Ordering::Greater
20490                } else {
20491                    Ordering::Less
20492                }
20493            }) {
20494                Ok(i) | Err(i) => i,
20495            };
20496            for range in &ranges[start_ix..] {
20497                if range
20498                    .start
20499                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20500                    .is_ge()
20501                {
20502                    break;
20503                }
20504
20505                let start = range.start.to_display_point(display_snapshot);
20506                let end = range.end.to_display_point(display_snapshot);
20507                results.push((start..end, color))
20508            }
20509        }
20510        results
20511    }
20512
20513    /// Get the text ranges corresponding to the redaction query
20514    pub fn redacted_ranges(
20515        &self,
20516        search_range: Range<Anchor>,
20517        display_snapshot: &DisplaySnapshot,
20518        cx: &App,
20519    ) -> Vec<Range<DisplayPoint>> {
20520        display_snapshot
20521            .buffer_snapshot()
20522            .redacted_ranges(search_range, |file| {
20523                if let Some(file) = file {
20524                    file.is_private()
20525                        && EditorSettings::get(
20526                            Some(SettingsLocation {
20527                                worktree_id: file.worktree_id(cx),
20528                                path: file.path().as_ref(),
20529                            }),
20530                            cx,
20531                        )
20532                        .redact_private_values
20533                } else {
20534                    false
20535                }
20536            })
20537            .map(|range| {
20538                range.start.to_display_point(display_snapshot)
20539                    ..range.end.to_display_point(display_snapshot)
20540            })
20541            .collect()
20542    }
20543
20544    pub fn highlight_text_key<T: 'static>(
20545        &mut self,
20546        key: usize,
20547        ranges: Vec<Range<Anchor>>,
20548        style: HighlightStyle,
20549        cx: &mut Context<Self>,
20550    ) {
20551        self.display_map.update(cx, |map, _| {
20552            map.highlight_text(
20553                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20554                ranges,
20555                style,
20556            );
20557        });
20558        cx.notify();
20559    }
20560
20561    pub fn highlight_text<T: 'static>(
20562        &mut self,
20563        ranges: Vec<Range<Anchor>>,
20564        style: HighlightStyle,
20565        cx: &mut Context<Self>,
20566    ) {
20567        self.display_map.update(cx, |map, _| {
20568            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20569        });
20570        cx.notify();
20571    }
20572
20573    pub fn text_highlights<'a, T: 'static>(
20574        &'a self,
20575        cx: &'a App,
20576    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20577        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20578    }
20579
20580    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20581        let cleared = self
20582            .display_map
20583            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20584        if cleared {
20585            cx.notify();
20586        }
20587    }
20588
20589    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20590        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20591            && self.focus_handle.is_focused(window)
20592    }
20593
20594    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20595        self.show_cursor_when_unfocused = is_enabled;
20596        cx.notify();
20597    }
20598
20599    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20600        cx.notify();
20601    }
20602
20603    fn on_debug_session_event(
20604        &mut self,
20605        _session: Entity<Session>,
20606        event: &SessionEvent,
20607        cx: &mut Context<Self>,
20608    ) {
20609        if let SessionEvent::InvalidateInlineValue = event {
20610            self.refresh_inline_values(cx);
20611        }
20612    }
20613
20614    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20615        let Some(project) = self.project.clone() else {
20616            return;
20617        };
20618
20619        if !self.inline_value_cache.enabled {
20620            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20621            self.splice_inlays(&inlays, Vec::new(), cx);
20622            return;
20623        }
20624
20625        let current_execution_position = self
20626            .highlighted_rows
20627            .get(&TypeId::of::<ActiveDebugLine>())
20628            .and_then(|lines| lines.last().map(|line| line.range.end));
20629
20630        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20631            let inline_values = editor
20632                .update(cx, |editor, cx| {
20633                    let Some(current_execution_position) = current_execution_position else {
20634                        return Some(Task::ready(Ok(Vec::new())));
20635                    };
20636
20637                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20638                        let snapshot = buffer.snapshot(cx);
20639
20640                        let excerpt = snapshot.excerpt_containing(
20641                            current_execution_position..current_execution_position,
20642                        )?;
20643
20644                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20645                    })?;
20646
20647                    let range =
20648                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20649
20650                    project.inline_values(buffer, range, cx)
20651                })
20652                .ok()
20653                .flatten()?
20654                .await
20655                .context("refreshing debugger inlays")
20656                .log_err()?;
20657
20658            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20659
20660            for (buffer_id, inline_value) in inline_values
20661                .into_iter()
20662                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20663            {
20664                buffer_inline_values
20665                    .entry(buffer_id)
20666                    .or_default()
20667                    .push(inline_value);
20668            }
20669
20670            editor
20671                .update(cx, |editor, cx| {
20672                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20673                    let mut new_inlays = Vec::default();
20674
20675                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20676                        let buffer_id = buffer_snapshot.remote_id();
20677                        buffer_inline_values
20678                            .get(&buffer_id)
20679                            .into_iter()
20680                            .flatten()
20681                            .for_each(|hint| {
20682                                let inlay = Inlay::debugger(
20683                                    post_inc(&mut editor.next_inlay_id),
20684                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20685                                    hint.text(),
20686                                );
20687                                if !inlay.text().chars().contains(&'\n') {
20688                                    new_inlays.push(inlay);
20689                                }
20690                            });
20691                    }
20692
20693                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20694                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20695
20696                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20697                })
20698                .ok()?;
20699            Some(())
20700        });
20701    }
20702
20703    fn on_buffer_event(
20704        &mut self,
20705        multibuffer: &Entity<MultiBuffer>,
20706        event: &multi_buffer::Event,
20707        window: &mut Window,
20708        cx: &mut Context<Self>,
20709    ) {
20710        match event {
20711            multi_buffer::Event::Edited { edited_buffer } => {
20712                self.scrollbar_marker_state.dirty = true;
20713                self.active_indent_guides_state.dirty = true;
20714                self.refresh_active_diagnostics(cx);
20715                self.refresh_code_actions(window, cx);
20716                self.refresh_selected_text_highlights(true, window, cx);
20717                self.refresh_single_line_folds(window, cx);
20718                refresh_matching_bracket_highlights(self, cx);
20719                if self.has_active_edit_prediction() {
20720                    self.update_visible_edit_prediction(window, cx);
20721                }
20722
20723                if let Some(buffer) = edited_buffer {
20724                    if buffer.read(cx).file().is_none() {
20725                        cx.emit(EditorEvent::TitleChanged);
20726                    }
20727
20728                    if self.project.is_some() {
20729                        let buffer_id = buffer.read(cx).remote_id();
20730                        self.register_buffer(buffer_id, cx);
20731                        self.update_lsp_data(Some(buffer_id), window, cx);
20732                        self.refresh_inlay_hints(
20733                            InlayHintRefreshReason::BufferEdited(buffer_id),
20734                            cx,
20735                        );
20736                    }
20737                }
20738
20739                cx.emit(EditorEvent::BufferEdited);
20740                cx.emit(SearchEvent::MatchesInvalidated);
20741
20742                let Some(project) = &self.project else { return };
20743                let (telemetry, is_via_ssh) = {
20744                    let project = project.read(cx);
20745                    let telemetry = project.client().telemetry().clone();
20746                    let is_via_ssh = project.is_via_remote_server();
20747                    (telemetry, is_via_ssh)
20748                };
20749                telemetry.log_edit_event("editor", is_via_ssh);
20750            }
20751            multi_buffer::Event::ExcerptsAdded {
20752                buffer,
20753                predecessor,
20754                excerpts,
20755            } => {
20756                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20757                let buffer_id = buffer.read(cx).remote_id();
20758                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20759                    && let Some(project) = &self.project
20760                {
20761                    update_uncommitted_diff_for_buffer(
20762                        cx.entity(),
20763                        project,
20764                        [buffer.clone()],
20765                        self.buffer.clone(),
20766                        cx,
20767                    )
20768                    .detach();
20769                }
20770                self.update_lsp_data(Some(buffer_id), window, cx);
20771                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20772                cx.emit(EditorEvent::ExcerptsAdded {
20773                    buffer: buffer.clone(),
20774                    predecessor: *predecessor,
20775                    excerpts: excerpts.clone(),
20776                });
20777            }
20778            multi_buffer::Event::ExcerptsRemoved {
20779                ids,
20780                removed_buffer_ids,
20781            } => {
20782                if let Some(inlay_hints) = &mut self.inlay_hints {
20783                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
20784                }
20785                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20786                for buffer_id in removed_buffer_ids {
20787                    self.registered_buffers.remove(buffer_id);
20788                }
20789                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20790                cx.emit(EditorEvent::ExcerptsRemoved {
20791                    ids: ids.clone(),
20792                    removed_buffer_ids: removed_buffer_ids.clone(),
20793                });
20794            }
20795            multi_buffer::Event::ExcerptsEdited {
20796                excerpt_ids,
20797                buffer_ids,
20798            } => {
20799                self.display_map.update(cx, |map, cx| {
20800                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20801                });
20802                cx.emit(EditorEvent::ExcerptsEdited {
20803                    ids: excerpt_ids.clone(),
20804                });
20805            }
20806            multi_buffer::Event::ExcerptsExpanded { ids } => {
20807                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20808                self.refresh_document_highlights(cx);
20809                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20810            }
20811            multi_buffer::Event::Reparsed(buffer_id) => {
20812                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20813                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20814
20815                cx.emit(EditorEvent::Reparsed(*buffer_id));
20816            }
20817            multi_buffer::Event::DiffHunksToggled => {
20818                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20819            }
20820            multi_buffer::Event::LanguageChanged(buffer_id) => {
20821                self.registered_buffers.remove(&buffer_id);
20822                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20823                cx.emit(EditorEvent::Reparsed(*buffer_id));
20824                cx.notify();
20825            }
20826            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20827            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20828            multi_buffer::Event::FileHandleChanged
20829            | multi_buffer::Event::Reloaded
20830            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20831            multi_buffer::Event::DiagnosticsUpdated => {
20832                self.update_diagnostics_state(window, cx);
20833            }
20834            _ => {}
20835        };
20836    }
20837
20838    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20839        if !self.diagnostics_enabled() {
20840            return;
20841        }
20842        self.refresh_active_diagnostics(cx);
20843        self.refresh_inline_diagnostics(true, window, cx);
20844        self.scrollbar_marker_state.dirty = true;
20845        cx.notify();
20846    }
20847
20848    pub fn start_temporary_diff_override(&mut self) {
20849        self.load_diff_task.take();
20850        self.temporary_diff_override = true;
20851    }
20852
20853    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20854        self.temporary_diff_override = false;
20855        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20856        self.buffer.update(cx, |buffer, cx| {
20857            buffer.set_all_diff_hunks_collapsed(cx);
20858        });
20859
20860        if let Some(project) = self.project.clone() {
20861            self.load_diff_task = Some(
20862                update_uncommitted_diff_for_buffer(
20863                    cx.entity(),
20864                    &project,
20865                    self.buffer.read(cx).all_buffers(),
20866                    self.buffer.clone(),
20867                    cx,
20868                )
20869                .shared(),
20870            );
20871        }
20872    }
20873
20874    fn on_display_map_changed(
20875        &mut self,
20876        _: Entity<DisplayMap>,
20877        _: &mut Window,
20878        cx: &mut Context<Self>,
20879    ) {
20880        cx.notify();
20881    }
20882
20883    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20884        if self.diagnostics_enabled() {
20885            let new_severity = EditorSettings::get_global(cx)
20886                .diagnostics_max_severity
20887                .unwrap_or(DiagnosticSeverity::Hint);
20888            self.set_max_diagnostics_severity(new_severity, cx);
20889        }
20890        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20891        self.update_edit_prediction_settings(cx);
20892        self.refresh_edit_prediction(true, false, window, cx);
20893        self.refresh_inline_values(cx);
20894        self.refresh_inlay_hints(
20895            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20896                self.selections.newest_anchor().head(),
20897                &self.buffer.read(cx).snapshot(cx),
20898                cx,
20899            )),
20900            cx,
20901        );
20902
20903        let old_cursor_shape = self.cursor_shape;
20904        let old_show_breadcrumbs = self.show_breadcrumbs;
20905
20906        {
20907            let editor_settings = EditorSettings::get_global(cx);
20908            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20909            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20910            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20911            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20912        }
20913
20914        if old_cursor_shape != self.cursor_shape {
20915            cx.emit(EditorEvent::CursorShapeChanged);
20916        }
20917
20918        if old_show_breadcrumbs != self.show_breadcrumbs {
20919            cx.emit(EditorEvent::BreadcrumbsChanged);
20920        }
20921
20922        let project_settings = ProjectSettings::get_global(cx);
20923        self.serialize_dirty_buffers =
20924            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20925
20926        if self.mode.is_full() {
20927            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20928            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20929            if self.show_inline_diagnostics != show_inline_diagnostics {
20930                self.show_inline_diagnostics = show_inline_diagnostics;
20931                self.refresh_inline_diagnostics(false, window, cx);
20932            }
20933
20934            if self.git_blame_inline_enabled != inline_blame_enabled {
20935                self.toggle_git_blame_inline_internal(false, window, cx);
20936            }
20937
20938            let minimap_settings = EditorSettings::get_global(cx).minimap;
20939            if self.minimap_visibility != MinimapVisibility::Disabled {
20940                if self.minimap_visibility.settings_visibility()
20941                    != minimap_settings.minimap_enabled()
20942                {
20943                    self.set_minimap_visibility(
20944                        MinimapVisibility::for_mode(self.mode(), cx),
20945                        window,
20946                        cx,
20947                    );
20948                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20949                    minimap_entity.update(cx, |minimap_editor, cx| {
20950                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20951                    })
20952                }
20953            }
20954        }
20955
20956        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20957            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20958        }) {
20959            if !inlay_splice.is_empty() {
20960                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20961            }
20962            self.refresh_colors_for_visible_range(None, window, cx);
20963        }
20964
20965        cx.notify();
20966    }
20967
20968    pub fn set_searchable(&mut self, searchable: bool) {
20969        self.searchable = searchable;
20970    }
20971
20972    pub fn searchable(&self) -> bool {
20973        self.searchable
20974    }
20975
20976    fn open_proposed_changes_editor(
20977        &mut self,
20978        _: &OpenProposedChangesEditor,
20979        window: &mut Window,
20980        cx: &mut Context<Self>,
20981    ) {
20982        let Some(workspace) = self.workspace() else {
20983            cx.propagate();
20984            return;
20985        };
20986
20987        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
20988        let multi_buffer = self.buffer.read(cx);
20989        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20990        let mut new_selections_by_buffer = HashMap::default();
20991        for selection in selections {
20992            for (buffer, range, _) in
20993                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20994            {
20995                let mut range = range.to_point(buffer);
20996                range.start.column = 0;
20997                range.end.column = buffer.line_len(range.end.row);
20998                new_selections_by_buffer
20999                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
21000                    .or_insert(Vec::new())
21001                    .push(range)
21002            }
21003        }
21004
21005        let proposed_changes_buffers = new_selections_by_buffer
21006            .into_iter()
21007            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
21008            .collect::<Vec<_>>();
21009        let proposed_changes_editor = cx.new(|cx| {
21010            ProposedChangesEditor::new(
21011                "Proposed changes",
21012                proposed_changes_buffers,
21013                self.project.clone(),
21014                window,
21015                cx,
21016            )
21017        });
21018
21019        window.defer(cx, move |window, cx| {
21020            workspace.update(cx, |workspace, cx| {
21021                workspace.active_pane().update(cx, |pane, cx| {
21022                    pane.add_item(
21023                        Box::new(proposed_changes_editor),
21024                        true,
21025                        true,
21026                        None,
21027                        window,
21028                        cx,
21029                    );
21030                });
21031            });
21032        });
21033    }
21034
21035    pub fn open_excerpts_in_split(
21036        &mut self,
21037        _: &OpenExcerptsSplit,
21038        window: &mut Window,
21039        cx: &mut Context<Self>,
21040    ) {
21041        self.open_excerpts_common(None, true, window, cx)
21042    }
21043
21044    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21045        self.open_excerpts_common(None, false, window, cx)
21046    }
21047
21048    fn open_excerpts_common(
21049        &mut self,
21050        jump_data: Option<JumpData>,
21051        split: bool,
21052        window: &mut Window,
21053        cx: &mut Context<Self>,
21054    ) {
21055        let Some(workspace) = self.workspace() else {
21056            cx.propagate();
21057            return;
21058        };
21059
21060        if self.buffer.read(cx).is_singleton() {
21061            cx.propagate();
21062            return;
21063        }
21064
21065        let mut new_selections_by_buffer = HashMap::default();
21066        match &jump_data {
21067            Some(JumpData::MultiBufferPoint {
21068                excerpt_id,
21069                position,
21070                anchor,
21071                line_offset_from_top,
21072            }) => {
21073                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21074                if let Some(buffer) = multi_buffer_snapshot
21075                    .buffer_id_for_excerpt(*excerpt_id)
21076                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21077                {
21078                    let buffer_snapshot = buffer.read(cx).snapshot();
21079                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21080                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21081                    } else {
21082                        buffer_snapshot.clip_point(*position, Bias::Left)
21083                    };
21084                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21085                    new_selections_by_buffer.insert(
21086                        buffer,
21087                        (
21088                            vec![jump_to_offset..jump_to_offset],
21089                            Some(*line_offset_from_top),
21090                        ),
21091                    );
21092                }
21093            }
21094            Some(JumpData::MultiBufferRow {
21095                row,
21096                line_offset_from_top,
21097            }) => {
21098                let point = MultiBufferPoint::new(row.0, 0);
21099                if let Some((buffer, buffer_point, _)) =
21100                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21101                {
21102                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21103                    new_selections_by_buffer
21104                        .entry(buffer)
21105                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21106                        .0
21107                        .push(buffer_offset..buffer_offset)
21108                }
21109            }
21110            None => {
21111                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21112                let multi_buffer = self.buffer.read(cx);
21113                for selection in selections {
21114                    for (snapshot, range, _, anchor) in multi_buffer
21115                        .snapshot(cx)
21116                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21117                    {
21118                        if let Some(anchor) = anchor {
21119                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21120                            else {
21121                                continue;
21122                            };
21123                            let offset = text::ToOffset::to_offset(
21124                                &anchor.text_anchor,
21125                                &buffer_handle.read(cx).snapshot(),
21126                            );
21127                            let range = offset..offset;
21128                            new_selections_by_buffer
21129                                .entry(buffer_handle)
21130                                .or_insert((Vec::new(), None))
21131                                .0
21132                                .push(range)
21133                        } else {
21134                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21135                            else {
21136                                continue;
21137                            };
21138                            new_selections_by_buffer
21139                                .entry(buffer_handle)
21140                                .or_insert((Vec::new(), None))
21141                                .0
21142                                .push(range)
21143                        }
21144                    }
21145                }
21146            }
21147        }
21148
21149        new_selections_by_buffer
21150            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21151
21152        if new_selections_by_buffer.is_empty() {
21153            return;
21154        }
21155
21156        // We defer the pane interaction because we ourselves are a workspace item
21157        // and activating a new item causes the pane to call a method on us reentrantly,
21158        // which panics if we're on the stack.
21159        window.defer(cx, move |window, cx| {
21160            workspace.update(cx, |workspace, cx| {
21161                let pane = if split {
21162                    workspace.adjacent_pane(window, cx)
21163                } else {
21164                    workspace.active_pane().clone()
21165                };
21166
21167                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21168                    let editor = buffer
21169                        .read(cx)
21170                        .file()
21171                        .is_none()
21172                        .then(|| {
21173                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21174                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21175                            // Instead, we try to activate the existing editor in the pane first.
21176                            let (editor, pane_item_index) =
21177                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21178                                    let editor = item.downcast::<Editor>()?;
21179                                    let singleton_buffer =
21180                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21181                                    if singleton_buffer == buffer {
21182                                        Some((editor, i))
21183                                    } else {
21184                                        None
21185                                    }
21186                                })?;
21187                            pane.update(cx, |pane, cx| {
21188                                pane.activate_item(pane_item_index, true, true, window, cx)
21189                            });
21190                            Some(editor)
21191                        })
21192                        .flatten()
21193                        .unwrap_or_else(|| {
21194                            workspace.open_project_item::<Self>(
21195                                pane.clone(),
21196                                buffer,
21197                                true,
21198                                true,
21199                                window,
21200                                cx,
21201                            )
21202                        });
21203
21204                    editor.update(cx, |editor, cx| {
21205                        let autoscroll = match scroll_offset {
21206                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21207                            None => Autoscroll::newest(),
21208                        };
21209                        let nav_history = editor.nav_history.take();
21210                        editor.change_selections(
21211                            SelectionEffects::scroll(autoscroll),
21212                            window,
21213                            cx,
21214                            |s| {
21215                                s.select_ranges(ranges);
21216                            },
21217                        );
21218                        editor.nav_history = nav_history;
21219                    });
21220                }
21221            })
21222        });
21223    }
21224
21225    // For now, don't allow opening excerpts in buffers that aren't backed by
21226    // regular project files.
21227    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21228        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21229    }
21230
21231    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21232        let snapshot = self.buffer.read(cx).read(cx);
21233        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21234        Some(
21235            ranges
21236                .iter()
21237                .map(move |range| {
21238                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21239                })
21240                .collect(),
21241        )
21242    }
21243
21244    fn selection_replacement_ranges(
21245        &self,
21246        range: Range<OffsetUtf16>,
21247        cx: &mut App,
21248    ) -> Vec<Range<OffsetUtf16>> {
21249        let selections = self
21250            .selections
21251            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21252        let newest_selection = selections
21253            .iter()
21254            .max_by_key(|selection| selection.id)
21255            .unwrap();
21256        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21257        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21258        let snapshot = self.buffer.read(cx).read(cx);
21259        selections
21260            .into_iter()
21261            .map(|mut selection| {
21262                selection.start.0 =
21263                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21264                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21265                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21266                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21267            })
21268            .collect()
21269    }
21270
21271    fn report_editor_event(
21272        &self,
21273        reported_event: ReportEditorEvent,
21274        file_extension: Option<String>,
21275        cx: &App,
21276    ) {
21277        if cfg!(any(test, feature = "test-support")) {
21278            return;
21279        }
21280
21281        let Some(project) = &self.project else { return };
21282
21283        // If None, we are in a file without an extension
21284        let file = self
21285            .buffer
21286            .read(cx)
21287            .as_singleton()
21288            .and_then(|b| b.read(cx).file());
21289        let file_extension = file_extension.or(file
21290            .as_ref()
21291            .and_then(|file| Path::new(file.file_name(cx)).extension())
21292            .and_then(|e| e.to_str())
21293            .map(|a| a.to_string()));
21294
21295        let vim_mode = vim_enabled(cx);
21296
21297        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21298        let copilot_enabled = edit_predictions_provider
21299            == language::language_settings::EditPredictionProvider::Copilot;
21300        let copilot_enabled_for_language = self
21301            .buffer
21302            .read(cx)
21303            .language_settings(cx)
21304            .show_edit_predictions;
21305
21306        let project = project.read(cx);
21307        let event_type = reported_event.event_type();
21308
21309        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21310            telemetry::event!(
21311                event_type,
21312                type = if auto_saved {"autosave"} else {"manual"},
21313                file_extension,
21314                vim_mode,
21315                copilot_enabled,
21316                copilot_enabled_for_language,
21317                edit_predictions_provider,
21318                is_via_ssh = project.is_via_remote_server(),
21319            );
21320        } else {
21321            telemetry::event!(
21322                event_type,
21323                file_extension,
21324                vim_mode,
21325                copilot_enabled,
21326                copilot_enabled_for_language,
21327                edit_predictions_provider,
21328                is_via_ssh = project.is_via_remote_server(),
21329            );
21330        };
21331    }
21332
21333    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21334    /// with each line being an array of {text, highlight} objects.
21335    fn copy_highlight_json(
21336        &mut self,
21337        _: &CopyHighlightJson,
21338        window: &mut Window,
21339        cx: &mut Context<Self>,
21340    ) {
21341        #[derive(Serialize)]
21342        struct Chunk<'a> {
21343            text: String,
21344            highlight: Option<&'a str>,
21345        }
21346
21347        let snapshot = self.buffer.read(cx).snapshot(cx);
21348        let range = self
21349            .selected_text_range(false, window, cx)
21350            .and_then(|selection| {
21351                if selection.range.is_empty() {
21352                    None
21353                } else {
21354                    Some(selection.range)
21355                }
21356            })
21357            .unwrap_or_else(|| 0..snapshot.len());
21358
21359        let chunks = snapshot.chunks(range, true);
21360        let mut lines = Vec::new();
21361        let mut line: VecDeque<Chunk> = VecDeque::new();
21362
21363        let Some(style) = self.style.as_ref() else {
21364            return;
21365        };
21366
21367        for chunk in chunks {
21368            let highlight = chunk
21369                .syntax_highlight_id
21370                .and_then(|id| id.name(&style.syntax));
21371            let mut chunk_lines = chunk.text.split('\n').peekable();
21372            while let Some(text) = chunk_lines.next() {
21373                let mut merged_with_last_token = false;
21374                if let Some(last_token) = line.back_mut()
21375                    && last_token.highlight == highlight
21376                {
21377                    last_token.text.push_str(text);
21378                    merged_with_last_token = true;
21379                }
21380
21381                if !merged_with_last_token {
21382                    line.push_back(Chunk {
21383                        text: text.into(),
21384                        highlight,
21385                    });
21386                }
21387
21388                if chunk_lines.peek().is_some() {
21389                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21390                        line.pop_front();
21391                    }
21392                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21393                        line.pop_back();
21394                    }
21395
21396                    lines.push(mem::take(&mut line));
21397                }
21398            }
21399        }
21400
21401        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21402            return;
21403        };
21404        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21405    }
21406
21407    pub fn open_context_menu(
21408        &mut self,
21409        _: &OpenContextMenu,
21410        window: &mut Window,
21411        cx: &mut Context<Self>,
21412    ) {
21413        self.request_autoscroll(Autoscroll::newest(), cx);
21414        let position = self
21415            .selections
21416            .newest_display(&self.display_snapshot(cx))
21417            .start;
21418        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21419    }
21420
21421    pub fn replay_insert_event(
21422        &mut self,
21423        text: &str,
21424        relative_utf16_range: Option<Range<isize>>,
21425        window: &mut Window,
21426        cx: &mut Context<Self>,
21427    ) {
21428        if !self.input_enabled {
21429            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21430            return;
21431        }
21432        if let Some(relative_utf16_range) = relative_utf16_range {
21433            let selections = self
21434                .selections
21435                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21436            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21437                let new_ranges = selections.into_iter().map(|range| {
21438                    let start = OffsetUtf16(
21439                        range
21440                            .head()
21441                            .0
21442                            .saturating_add_signed(relative_utf16_range.start),
21443                    );
21444                    let end = OffsetUtf16(
21445                        range
21446                            .head()
21447                            .0
21448                            .saturating_add_signed(relative_utf16_range.end),
21449                    );
21450                    start..end
21451                });
21452                s.select_ranges(new_ranges);
21453            });
21454        }
21455
21456        self.handle_input(text, window, cx);
21457    }
21458
21459    pub fn is_focused(&self, window: &Window) -> bool {
21460        self.focus_handle.is_focused(window)
21461    }
21462
21463    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21464        cx.emit(EditorEvent::Focused);
21465
21466        if let Some(descendant) = self
21467            .last_focused_descendant
21468            .take()
21469            .and_then(|descendant| descendant.upgrade())
21470        {
21471            window.focus(&descendant);
21472        } else {
21473            if let Some(blame) = self.blame.as_ref() {
21474                blame.update(cx, GitBlame::focus)
21475            }
21476
21477            self.blink_manager.update(cx, BlinkManager::enable);
21478            self.show_cursor_names(window, cx);
21479            self.buffer.update(cx, |buffer, cx| {
21480                buffer.finalize_last_transaction(cx);
21481                if self.leader_id.is_none() {
21482                    buffer.set_active_selections(
21483                        &self.selections.disjoint_anchors_arc(),
21484                        self.selections.line_mode(),
21485                        self.cursor_shape,
21486                        cx,
21487                    );
21488                }
21489            });
21490        }
21491    }
21492
21493    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21494        cx.emit(EditorEvent::FocusedIn)
21495    }
21496
21497    fn handle_focus_out(
21498        &mut self,
21499        event: FocusOutEvent,
21500        _window: &mut Window,
21501        cx: &mut Context<Self>,
21502    ) {
21503        if event.blurred != self.focus_handle {
21504            self.last_focused_descendant = Some(event.blurred);
21505        }
21506        self.selection_drag_state = SelectionDragState::None;
21507        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21508    }
21509
21510    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21511        self.blink_manager.update(cx, BlinkManager::disable);
21512        self.buffer
21513            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21514
21515        if let Some(blame) = self.blame.as_ref() {
21516            blame.update(cx, GitBlame::blur)
21517        }
21518        if !self.hover_state.focused(window, cx) {
21519            hide_hover(self, cx);
21520        }
21521        if !self
21522            .context_menu
21523            .borrow()
21524            .as_ref()
21525            .is_some_and(|context_menu| context_menu.focused(window, cx))
21526        {
21527            self.hide_context_menu(window, cx);
21528        }
21529        self.take_active_edit_prediction(cx);
21530        cx.emit(EditorEvent::Blurred);
21531        cx.notify();
21532    }
21533
21534    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21535        let mut pending: String = window
21536            .pending_input_keystrokes()
21537            .into_iter()
21538            .flatten()
21539            .filter_map(|keystroke| {
21540                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21541                    keystroke.key_char.clone()
21542                } else {
21543                    None
21544                }
21545            })
21546            .collect();
21547
21548        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21549            pending = "".to_string();
21550        }
21551
21552        let existing_pending = self
21553            .text_highlights::<PendingInput>(cx)
21554            .map(|(_, ranges)| ranges.to_vec());
21555        if existing_pending.is_none() && pending.is_empty() {
21556            return;
21557        }
21558        let transaction =
21559            self.transact(window, cx, |this, window, cx| {
21560                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21561                let edits = selections
21562                    .iter()
21563                    .map(|selection| (selection.end..selection.end, pending.clone()));
21564                this.edit(edits, cx);
21565                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21566                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21567                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21568                    }));
21569                });
21570                if let Some(existing_ranges) = existing_pending {
21571                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21572                    this.edit(edits, cx);
21573                }
21574            });
21575
21576        let snapshot = self.snapshot(window, cx);
21577        let ranges = self
21578            .selections
21579            .all::<usize>(&snapshot.display_snapshot)
21580            .into_iter()
21581            .map(|selection| {
21582                snapshot.buffer_snapshot().anchor_after(selection.end)
21583                    ..snapshot
21584                        .buffer_snapshot()
21585                        .anchor_before(selection.end + pending.len())
21586            })
21587            .collect();
21588
21589        if pending.is_empty() {
21590            self.clear_highlights::<PendingInput>(cx);
21591        } else {
21592            self.highlight_text::<PendingInput>(
21593                ranges,
21594                HighlightStyle {
21595                    underline: Some(UnderlineStyle {
21596                        thickness: px(1.),
21597                        color: None,
21598                        wavy: false,
21599                    }),
21600                    ..Default::default()
21601                },
21602                cx,
21603            );
21604        }
21605
21606        self.ime_transaction = self.ime_transaction.or(transaction);
21607        if let Some(transaction) = self.ime_transaction {
21608            self.buffer.update(cx, |buffer, cx| {
21609                buffer.group_until_transaction(transaction, cx);
21610            });
21611        }
21612
21613        if self.text_highlights::<PendingInput>(cx).is_none() {
21614            self.ime_transaction.take();
21615        }
21616    }
21617
21618    pub fn register_action_renderer(
21619        &mut self,
21620        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21621    ) -> Subscription {
21622        let id = self.next_editor_action_id.post_inc();
21623        self.editor_actions
21624            .borrow_mut()
21625            .insert(id, Box::new(listener));
21626
21627        let editor_actions = self.editor_actions.clone();
21628        Subscription::new(move || {
21629            editor_actions.borrow_mut().remove(&id);
21630        })
21631    }
21632
21633    pub fn register_action<A: Action>(
21634        &mut self,
21635        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21636    ) -> Subscription {
21637        let id = self.next_editor_action_id.post_inc();
21638        let listener = Arc::new(listener);
21639        self.editor_actions.borrow_mut().insert(
21640            id,
21641            Box::new(move |_, window, _| {
21642                let listener = listener.clone();
21643                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21644                    let action = action.downcast_ref().unwrap();
21645                    if phase == DispatchPhase::Bubble {
21646                        listener(action, window, cx)
21647                    }
21648                })
21649            }),
21650        );
21651
21652        let editor_actions = self.editor_actions.clone();
21653        Subscription::new(move || {
21654            editor_actions.borrow_mut().remove(&id);
21655        })
21656    }
21657
21658    pub fn file_header_size(&self) -> u32 {
21659        FILE_HEADER_HEIGHT
21660    }
21661
21662    pub fn restore(
21663        &mut self,
21664        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21665        window: &mut Window,
21666        cx: &mut Context<Self>,
21667    ) {
21668        let workspace = self.workspace();
21669        let project = self.project();
21670        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21671            let mut tasks = Vec::new();
21672            for (buffer_id, changes) in revert_changes {
21673                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21674                    buffer.update(cx, |buffer, cx| {
21675                        buffer.edit(
21676                            changes
21677                                .into_iter()
21678                                .map(|(range, text)| (range, text.to_string())),
21679                            None,
21680                            cx,
21681                        );
21682                    });
21683
21684                    if let Some(project) =
21685                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21686                    {
21687                        project.update(cx, |project, cx| {
21688                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21689                        })
21690                    }
21691                }
21692            }
21693            tasks
21694        });
21695        cx.spawn_in(window, async move |_, cx| {
21696            for (buffer, task) in save_tasks {
21697                let result = task.await;
21698                if result.is_err() {
21699                    let Some(path) = buffer
21700                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21701                        .ok()
21702                    else {
21703                        continue;
21704                    };
21705                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21706                        let Some(task) = cx
21707                            .update_window_entity(workspace, |workspace, window, cx| {
21708                                workspace
21709                                    .open_path_preview(path, None, false, false, false, window, cx)
21710                            })
21711                            .ok()
21712                        else {
21713                            continue;
21714                        };
21715                        task.await.log_err();
21716                    }
21717                }
21718            }
21719        })
21720        .detach();
21721        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21722            selections.refresh()
21723        });
21724    }
21725
21726    pub fn to_pixel_point(
21727        &self,
21728        source: multi_buffer::Anchor,
21729        editor_snapshot: &EditorSnapshot,
21730        window: &mut Window,
21731    ) -> Option<gpui::Point<Pixels>> {
21732        let source_point = source.to_display_point(editor_snapshot);
21733        self.display_to_pixel_point(source_point, editor_snapshot, window)
21734    }
21735
21736    pub fn display_to_pixel_point(
21737        &self,
21738        source: DisplayPoint,
21739        editor_snapshot: &EditorSnapshot,
21740        window: &mut Window,
21741    ) -> Option<gpui::Point<Pixels>> {
21742        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21743        let text_layout_details = self.text_layout_details(window);
21744        let scroll_top = text_layout_details
21745            .scroll_anchor
21746            .scroll_position(editor_snapshot)
21747            .y;
21748
21749        if source.row().as_f64() < scroll_top.floor() {
21750            return None;
21751        }
21752        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21753        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21754        Some(gpui::Point::new(source_x, source_y))
21755    }
21756
21757    pub fn has_visible_completions_menu(&self) -> bool {
21758        !self.edit_prediction_preview_is_active()
21759            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21760                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21761            })
21762    }
21763
21764    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21765        if self.mode.is_minimap() {
21766            return;
21767        }
21768        self.addons
21769            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21770    }
21771
21772    pub fn unregister_addon<T: Addon>(&mut self) {
21773        self.addons.remove(&std::any::TypeId::of::<T>());
21774    }
21775
21776    pub fn addon<T: Addon>(&self) -> Option<&T> {
21777        let type_id = std::any::TypeId::of::<T>();
21778        self.addons
21779            .get(&type_id)
21780            .and_then(|item| item.to_any().downcast_ref::<T>())
21781    }
21782
21783    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21784        let type_id = std::any::TypeId::of::<T>();
21785        self.addons
21786            .get_mut(&type_id)
21787            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21788    }
21789
21790    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21791        let text_layout_details = self.text_layout_details(window);
21792        let style = &text_layout_details.editor_style;
21793        let font_id = window.text_system().resolve_font(&style.text.font());
21794        let font_size = style.text.font_size.to_pixels(window.rem_size());
21795        let line_height = style.text.line_height_in_pixels(window.rem_size());
21796        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21797        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21798
21799        CharacterDimensions {
21800            em_width,
21801            em_advance,
21802            line_height,
21803        }
21804    }
21805
21806    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21807        self.load_diff_task.clone()
21808    }
21809
21810    fn read_metadata_from_db(
21811        &mut self,
21812        item_id: u64,
21813        workspace_id: WorkspaceId,
21814        window: &mut Window,
21815        cx: &mut Context<Editor>,
21816    ) {
21817        if self.buffer_kind(cx) == ItemBufferKind::Singleton
21818            && !self.mode.is_minimap()
21819            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21820        {
21821            let buffer_snapshot = OnceCell::new();
21822
21823            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21824                && !folds.is_empty()
21825            {
21826                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21827                self.fold_ranges(
21828                    folds
21829                        .into_iter()
21830                        .map(|(start, end)| {
21831                            snapshot.clip_offset(start, Bias::Left)
21832                                ..snapshot.clip_offset(end, Bias::Right)
21833                        })
21834                        .collect(),
21835                    false,
21836                    window,
21837                    cx,
21838                );
21839            }
21840
21841            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21842                && !selections.is_empty()
21843            {
21844                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21845                // skip adding the initial selection to selection history
21846                self.selection_history.mode = SelectionHistoryMode::Skipping;
21847                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21848                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21849                        snapshot.clip_offset(start, Bias::Left)
21850                            ..snapshot.clip_offset(end, Bias::Right)
21851                    }));
21852                });
21853                self.selection_history.mode = SelectionHistoryMode::Normal;
21854            };
21855        }
21856
21857        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21858    }
21859
21860    fn update_lsp_data(
21861        &mut self,
21862        for_buffer: Option<BufferId>,
21863        window: &mut Window,
21864        cx: &mut Context<'_, Self>,
21865    ) {
21866        self.pull_diagnostics(for_buffer, window, cx);
21867        self.refresh_colors_for_visible_range(for_buffer, window, cx);
21868    }
21869
21870    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
21871        if self.ignore_lsp_data() {
21872            return;
21873        }
21874        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
21875            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
21876        }
21877    }
21878
21879    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
21880        if !self.registered_buffers.contains_key(&buffer_id)
21881            && let Some(project) = self.project.as_ref()
21882        {
21883            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
21884                project.update(cx, |project, cx| {
21885                    self.registered_buffers.insert(
21886                        buffer_id,
21887                        project.register_buffer_with_language_servers(&buffer, cx),
21888                    );
21889                });
21890            } else {
21891                self.registered_buffers.remove(&buffer_id);
21892            }
21893        }
21894    }
21895
21896    fn ignore_lsp_data(&self) -> bool {
21897        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
21898        // skip any LSP updates for it.
21899        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
21900    }
21901}
21902
21903fn edit_for_markdown_paste<'a>(
21904    buffer: &MultiBufferSnapshot,
21905    range: Range<usize>,
21906    to_insert: &'a str,
21907    url: Option<url::Url>,
21908) -> (Range<usize>, Cow<'a, str>) {
21909    if url.is_none() {
21910        return (range, Cow::Borrowed(to_insert));
21911    };
21912
21913    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
21914
21915    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
21916        Cow::Borrowed(to_insert)
21917    } else {
21918        Cow::Owned(format!("[{old_text}]({to_insert})"))
21919    };
21920    (range, new_text)
21921}
21922
21923fn vim_enabled(cx: &App) -> bool {
21924    vim_mode_setting::VimModeSetting::try_get(cx)
21925        .map(|vim_mode| vim_mode.0)
21926        .unwrap_or(false)
21927}
21928
21929fn process_completion_for_edit(
21930    completion: &Completion,
21931    intent: CompletionIntent,
21932    buffer: &Entity<Buffer>,
21933    cursor_position: &text::Anchor,
21934    cx: &mut Context<Editor>,
21935) -> CompletionEdit {
21936    let buffer = buffer.read(cx);
21937    let buffer_snapshot = buffer.snapshot();
21938    let (snippet, new_text) = if completion.is_snippet() {
21939        let mut snippet_source = completion.new_text.clone();
21940        // Workaround for typescript language server issues so that methods don't expand within
21941        // strings and functions with type expressions. The previous point is used because the query
21942        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21943        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
21944        let previous_point = if previous_point.column > 0 {
21945            cursor_position.to_previous_offset(&buffer_snapshot)
21946        } else {
21947            cursor_position.to_offset(&buffer_snapshot)
21948        };
21949        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21950            && scope.prefers_label_for_snippet_in_completion()
21951            && let Some(label) = completion.label()
21952            && matches!(
21953                completion.kind(),
21954                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21955            )
21956        {
21957            snippet_source = label;
21958        }
21959        match Snippet::parse(&snippet_source).log_err() {
21960            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21961            None => (None, completion.new_text.clone()),
21962        }
21963    } else {
21964        (None, completion.new_text.clone())
21965    };
21966
21967    let mut range_to_replace = {
21968        let replace_range = &completion.replace_range;
21969        if let CompletionSource::Lsp {
21970            insert_range: Some(insert_range),
21971            ..
21972        } = &completion.source
21973        {
21974            debug_assert_eq!(
21975                insert_range.start, replace_range.start,
21976                "insert_range and replace_range should start at the same position"
21977            );
21978            debug_assert!(
21979                insert_range
21980                    .start
21981                    .cmp(cursor_position, &buffer_snapshot)
21982                    .is_le(),
21983                "insert_range should start before or at cursor position"
21984            );
21985            debug_assert!(
21986                replace_range
21987                    .start
21988                    .cmp(cursor_position, &buffer_snapshot)
21989                    .is_le(),
21990                "replace_range should start before or at cursor position"
21991            );
21992
21993            let should_replace = match intent {
21994                CompletionIntent::CompleteWithInsert => false,
21995                CompletionIntent::CompleteWithReplace => true,
21996                CompletionIntent::Complete | CompletionIntent::Compose => {
21997                    let insert_mode =
21998                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21999                            .completions
22000                            .lsp_insert_mode;
22001                    match insert_mode {
22002                        LspInsertMode::Insert => false,
22003                        LspInsertMode::Replace => true,
22004                        LspInsertMode::ReplaceSubsequence => {
22005                            let mut text_to_replace = buffer.chars_for_range(
22006                                buffer.anchor_before(replace_range.start)
22007                                    ..buffer.anchor_after(replace_range.end),
22008                            );
22009                            let mut current_needle = text_to_replace.next();
22010                            for haystack_ch in completion.label.text.chars() {
22011                                if let Some(needle_ch) = current_needle
22012                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22013                                {
22014                                    current_needle = text_to_replace.next();
22015                                }
22016                            }
22017                            current_needle.is_none()
22018                        }
22019                        LspInsertMode::ReplaceSuffix => {
22020                            if replace_range
22021                                .end
22022                                .cmp(cursor_position, &buffer_snapshot)
22023                                .is_gt()
22024                            {
22025                                let range_after_cursor = *cursor_position..replace_range.end;
22026                                let text_after_cursor = buffer
22027                                    .text_for_range(
22028                                        buffer.anchor_before(range_after_cursor.start)
22029                                            ..buffer.anchor_after(range_after_cursor.end),
22030                                    )
22031                                    .collect::<String>()
22032                                    .to_ascii_lowercase();
22033                                completion
22034                                    .label
22035                                    .text
22036                                    .to_ascii_lowercase()
22037                                    .ends_with(&text_after_cursor)
22038                            } else {
22039                                true
22040                            }
22041                        }
22042                    }
22043                }
22044            };
22045
22046            if should_replace {
22047                replace_range.clone()
22048            } else {
22049                insert_range.clone()
22050            }
22051        } else {
22052            replace_range.clone()
22053        }
22054    };
22055
22056    if range_to_replace
22057        .end
22058        .cmp(cursor_position, &buffer_snapshot)
22059        .is_lt()
22060    {
22061        range_to_replace.end = *cursor_position;
22062    }
22063
22064    CompletionEdit {
22065        new_text,
22066        replace_range: range_to_replace.to_offset(buffer),
22067        snippet,
22068    }
22069}
22070
22071struct CompletionEdit {
22072    new_text: String,
22073    replace_range: Range<usize>,
22074    snippet: Option<Snippet>,
22075}
22076
22077fn insert_extra_newline_brackets(
22078    buffer: &MultiBufferSnapshot,
22079    range: Range<usize>,
22080    language: &language::LanguageScope,
22081) -> bool {
22082    let leading_whitespace_len = buffer
22083        .reversed_chars_at(range.start)
22084        .take_while(|c| c.is_whitespace() && *c != '\n')
22085        .map(|c| c.len_utf8())
22086        .sum::<usize>();
22087    let trailing_whitespace_len = buffer
22088        .chars_at(range.end)
22089        .take_while(|c| c.is_whitespace() && *c != '\n')
22090        .map(|c| c.len_utf8())
22091        .sum::<usize>();
22092    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22093
22094    language.brackets().any(|(pair, enabled)| {
22095        let pair_start = pair.start.trim_end();
22096        let pair_end = pair.end.trim_start();
22097
22098        enabled
22099            && pair.newline
22100            && buffer.contains_str_at(range.end, pair_end)
22101            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22102    })
22103}
22104
22105fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22106    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22107        [(buffer, range, _)] => (*buffer, range.clone()),
22108        _ => return false,
22109    };
22110    let pair = {
22111        let mut result: Option<BracketMatch> = None;
22112
22113        for pair in buffer
22114            .all_bracket_ranges(range.clone())
22115            .filter(move |pair| {
22116                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22117            })
22118        {
22119            let len = pair.close_range.end - pair.open_range.start;
22120
22121            if let Some(existing) = &result {
22122                let existing_len = existing.close_range.end - existing.open_range.start;
22123                if len > existing_len {
22124                    continue;
22125                }
22126            }
22127
22128            result = Some(pair);
22129        }
22130
22131        result
22132    };
22133    let Some(pair) = pair else {
22134        return false;
22135    };
22136    pair.newline_only
22137        && buffer
22138            .chars_for_range(pair.open_range.end..range.start)
22139            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22140            .all(|c| c.is_whitespace() && c != '\n')
22141}
22142
22143fn update_uncommitted_diff_for_buffer(
22144    editor: Entity<Editor>,
22145    project: &Entity<Project>,
22146    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22147    buffer: Entity<MultiBuffer>,
22148    cx: &mut App,
22149) -> Task<()> {
22150    let mut tasks = Vec::new();
22151    project.update(cx, |project, cx| {
22152        for buffer in buffers {
22153            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22154                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22155            }
22156        }
22157    });
22158    cx.spawn(async move |cx| {
22159        let diffs = future::join_all(tasks).await;
22160        if editor
22161            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22162            .unwrap_or(false)
22163        {
22164            return;
22165        }
22166
22167        buffer
22168            .update(cx, |buffer, cx| {
22169                for diff in diffs.into_iter().flatten() {
22170                    buffer.add_diff(diff, cx);
22171                }
22172            })
22173            .ok();
22174    })
22175}
22176
22177fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22178    let tab_size = tab_size.get() as usize;
22179    let mut width = offset;
22180
22181    for ch in text.chars() {
22182        width += if ch == '\t' {
22183            tab_size - (width % tab_size)
22184        } else {
22185            1
22186        };
22187    }
22188
22189    width - offset
22190}
22191
22192#[cfg(test)]
22193mod tests {
22194    use super::*;
22195
22196    #[test]
22197    fn test_string_size_with_expanded_tabs() {
22198        let nz = |val| NonZeroU32::new(val).unwrap();
22199        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22200        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22201        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22202        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22203        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22204        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22205        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22206        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22207    }
22208}
22209
22210/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22211struct WordBreakingTokenizer<'a> {
22212    input: &'a str,
22213}
22214
22215impl<'a> WordBreakingTokenizer<'a> {
22216    fn new(input: &'a str) -> Self {
22217        Self { input }
22218    }
22219}
22220
22221fn is_char_ideographic(ch: char) -> bool {
22222    use unicode_script::Script::*;
22223    use unicode_script::UnicodeScript;
22224    matches!(ch.script(), Han | Tangut | Yi)
22225}
22226
22227fn is_grapheme_ideographic(text: &str) -> bool {
22228    text.chars().any(is_char_ideographic)
22229}
22230
22231fn is_grapheme_whitespace(text: &str) -> bool {
22232    text.chars().any(|x| x.is_whitespace())
22233}
22234
22235fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22236    text.chars()
22237        .next()
22238        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22239}
22240
22241#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22242enum WordBreakToken<'a> {
22243    Word { token: &'a str, grapheme_len: usize },
22244    InlineWhitespace { token: &'a str, grapheme_len: usize },
22245    Newline,
22246}
22247
22248impl<'a> Iterator for WordBreakingTokenizer<'a> {
22249    /// Yields a span, the count of graphemes in the token, and whether it was
22250    /// whitespace. Note that it also breaks at word boundaries.
22251    type Item = WordBreakToken<'a>;
22252
22253    fn next(&mut self) -> Option<Self::Item> {
22254        use unicode_segmentation::UnicodeSegmentation;
22255        if self.input.is_empty() {
22256            return None;
22257        }
22258
22259        let mut iter = self.input.graphemes(true).peekable();
22260        let mut offset = 0;
22261        let mut grapheme_len = 0;
22262        if let Some(first_grapheme) = iter.next() {
22263            let is_newline = first_grapheme == "\n";
22264            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22265            offset += first_grapheme.len();
22266            grapheme_len += 1;
22267            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22268                if let Some(grapheme) = iter.peek().copied()
22269                    && should_stay_with_preceding_ideograph(grapheme)
22270                {
22271                    offset += grapheme.len();
22272                    grapheme_len += 1;
22273                }
22274            } else {
22275                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22276                let mut next_word_bound = words.peek().copied();
22277                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22278                    next_word_bound = words.next();
22279                }
22280                while let Some(grapheme) = iter.peek().copied() {
22281                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22282                        break;
22283                    };
22284                    if is_grapheme_whitespace(grapheme) != is_whitespace
22285                        || (grapheme == "\n") != is_newline
22286                    {
22287                        break;
22288                    };
22289                    offset += grapheme.len();
22290                    grapheme_len += 1;
22291                    iter.next();
22292                }
22293            }
22294            let token = &self.input[..offset];
22295            self.input = &self.input[offset..];
22296            if token == "\n" {
22297                Some(WordBreakToken::Newline)
22298            } else if is_whitespace {
22299                Some(WordBreakToken::InlineWhitespace {
22300                    token,
22301                    grapheme_len,
22302                })
22303            } else {
22304                Some(WordBreakToken::Word {
22305                    token,
22306                    grapheme_len,
22307                })
22308            }
22309        } else {
22310            None
22311        }
22312    }
22313}
22314
22315#[test]
22316fn test_word_breaking_tokenizer() {
22317    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22318        ("", &[]),
22319        ("  ", &[whitespace("  ", 2)]),
22320        ("Ʒ", &[word("Ʒ", 1)]),
22321        ("Ǽ", &[word("Ǽ", 1)]),
22322        ("", &[word("", 1)]),
22323        ("⋑⋑", &[word("⋑⋑", 2)]),
22324        (
22325            "原理,进而",
22326            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22327        ),
22328        (
22329            "hello world",
22330            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22331        ),
22332        (
22333            "hello, world",
22334            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22335        ),
22336        (
22337            "  hello world",
22338            &[
22339                whitespace("  ", 2),
22340                word("hello", 5),
22341                whitespace(" ", 1),
22342                word("world", 5),
22343            ],
22344        ),
22345        (
22346            "这是什么 \n 钢笔",
22347            &[
22348                word("", 1),
22349                word("", 1),
22350                word("", 1),
22351                word("", 1),
22352                whitespace(" ", 1),
22353                newline(),
22354                whitespace(" ", 1),
22355                word("", 1),
22356                word("", 1),
22357            ],
22358        ),
22359        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22360    ];
22361
22362    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22363        WordBreakToken::Word {
22364            token,
22365            grapheme_len,
22366        }
22367    }
22368
22369    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22370        WordBreakToken::InlineWhitespace {
22371            token,
22372            grapheme_len,
22373        }
22374    }
22375
22376    fn newline() -> WordBreakToken<'static> {
22377        WordBreakToken::Newline
22378    }
22379
22380    for (input, result) in tests {
22381        assert_eq!(
22382            WordBreakingTokenizer::new(input)
22383                .collect::<Vec<_>>()
22384                .as_slice(),
22385            *result,
22386        );
22387    }
22388}
22389
22390fn wrap_with_prefix(
22391    first_line_prefix: String,
22392    subsequent_lines_prefix: String,
22393    unwrapped_text: String,
22394    wrap_column: usize,
22395    tab_size: NonZeroU32,
22396    preserve_existing_whitespace: bool,
22397) -> String {
22398    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22399    let subsequent_lines_prefix_len =
22400        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22401    let mut wrapped_text = String::new();
22402    let mut current_line = first_line_prefix;
22403    let mut is_first_line = true;
22404
22405    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22406    let mut current_line_len = first_line_prefix_len;
22407    let mut in_whitespace = false;
22408    for token in tokenizer {
22409        let have_preceding_whitespace = in_whitespace;
22410        match token {
22411            WordBreakToken::Word {
22412                token,
22413                grapheme_len,
22414            } => {
22415                in_whitespace = false;
22416                let current_prefix_len = if is_first_line {
22417                    first_line_prefix_len
22418                } else {
22419                    subsequent_lines_prefix_len
22420                };
22421                if current_line_len + grapheme_len > wrap_column
22422                    && current_line_len != current_prefix_len
22423                {
22424                    wrapped_text.push_str(current_line.trim_end());
22425                    wrapped_text.push('\n');
22426                    is_first_line = false;
22427                    current_line = subsequent_lines_prefix.clone();
22428                    current_line_len = subsequent_lines_prefix_len;
22429                }
22430                current_line.push_str(token);
22431                current_line_len += grapheme_len;
22432            }
22433            WordBreakToken::InlineWhitespace {
22434                mut token,
22435                mut grapheme_len,
22436            } => {
22437                in_whitespace = true;
22438                if have_preceding_whitespace && !preserve_existing_whitespace {
22439                    continue;
22440                }
22441                if !preserve_existing_whitespace {
22442                    // Keep a single whitespace grapheme as-is
22443                    if let Some(first) =
22444                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22445                    {
22446                        token = first;
22447                    } else {
22448                        token = " ";
22449                    }
22450                    grapheme_len = 1;
22451                }
22452                let current_prefix_len = if is_first_line {
22453                    first_line_prefix_len
22454                } else {
22455                    subsequent_lines_prefix_len
22456                };
22457                if current_line_len + grapheme_len > wrap_column {
22458                    wrapped_text.push_str(current_line.trim_end());
22459                    wrapped_text.push('\n');
22460                    is_first_line = false;
22461                    current_line = subsequent_lines_prefix.clone();
22462                    current_line_len = subsequent_lines_prefix_len;
22463                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22464                    current_line.push_str(token);
22465                    current_line_len += grapheme_len;
22466                }
22467            }
22468            WordBreakToken::Newline => {
22469                in_whitespace = true;
22470                let current_prefix_len = if is_first_line {
22471                    first_line_prefix_len
22472                } else {
22473                    subsequent_lines_prefix_len
22474                };
22475                if preserve_existing_whitespace {
22476                    wrapped_text.push_str(current_line.trim_end());
22477                    wrapped_text.push('\n');
22478                    is_first_line = false;
22479                    current_line = subsequent_lines_prefix.clone();
22480                    current_line_len = subsequent_lines_prefix_len;
22481                } else if have_preceding_whitespace {
22482                    continue;
22483                } else if current_line_len + 1 > wrap_column
22484                    && current_line_len != current_prefix_len
22485                {
22486                    wrapped_text.push_str(current_line.trim_end());
22487                    wrapped_text.push('\n');
22488                    is_first_line = false;
22489                    current_line = subsequent_lines_prefix.clone();
22490                    current_line_len = subsequent_lines_prefix_len;
22491                } else if current_line_len != current_prefix_len {
22492                    current_line.push(' ');
22493                    current_line_len += 1;
22494                }
22495            }
22496        }
22497    }
22498
22499    if !current_line.is_empty() {
22500        wrapped_text.push_str(&current_line);
22501    }
22502    wrapped_text
22503}
22504
22505#[test]
22506fn test_wrap_with_prefix() {
22507    assert_eq!(
22508        wrap_with_prefix(
22509            "# ".to_string(),
22510            "# ".to_string(),
22511            "abcdefg".to_string(),
22512            4,
22513            NonZeroU32::new(4).unwrap(),
22514            false,
22515        ),
22516        "# abcdefg"
22517    );
22518    assert_eq!(
22519        wrap_with_prefix(
22520            "".to_string(),
22521            "".to_string(),
22522            "\thello world".to_string(),
22523            8,
22524            NonZeroU32::new(4).unwrap(),
22525            false,
22526        ),
22527        "hello\nworld"
22528    );
22529    assert_eq!(
22530        wrap_with_prefix(
22531            "// ".to_string(),
22532            "// ".to_string(),
22533            "xx \nyy zz aa bb cc".to_string(),
22534            12,
22535            NonZeroU32::new(4).unwrap(),
22536            false,
22537        ),
22538        "// xx yy zz\n// aa bb cc"
22539    );
22540    assert_eq!(
22541        wrap_with_prefix(
22542            String::new(),
22543            String::new(),
22544            "这是什么 \n 钢笔".to_string(),
22545            3,
22546            NonZeroU32::new(4).unwrap(),
22547            false,
22548        ),
22549        "这是什\n么 钢\n"
22550    );
22551    assert_eq!(
22552        wrap_with_prefix(
22553            String::new(),
22554            String::new(),
22555            format!("foo{}bar", '\u{2009}'), // thin space
22556            80,
22557            NonZeroU32::new(4).unwrap(),
22558            false,
22559        ),
22560        format!("foo{}bar", '\u{2009}')
22561    );
22562}
22563
22564pub trait CollaborationHub {
22565    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22566    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22567    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22568}
22569
22570impl CollaborationHub for Entity<Project> {
22571    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22572        self.read(cx).collaborators()
22573    }
22574
22575    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22576        self.read(cx).user_store().read(cx).participant_indices()
22577    }
22578
22579    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22580        let this = self.read(cx);
22581        let user_ids = this.collaborators().values().map(|c| c.user_id);
22582        this.user_store().read(cx).participant_names(user_ids, cx)
22583    }
22584}
22585
22586pub trait SemanticsProvider {
22587    fn hover(
22588        &self,
22589        buffer: &Entity<Buffer>,
22590        position: text::Anchor,
22591        cx: &mut App,
22592    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22593
22594    fn inline_values(
22595        &self,
22596        buffer_handle: Entity<Buffer>,
22597        range: Range<text::Anchor>,
22598        cx: &mut App,
22599    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22600
22601    fn applicable_inlay_chunks(
22602        &self,
22603        buffer_id: BufferId,
22604        ranges: &[Range<text::Anchor>],
22605        cx: &App,
22606    ) -> Vec<Range<BufferRow>>;
22607
22608    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22609
22610    fn inlay_hints(
22611        &self,
22612        invalidate: InvalidationStrategy,
22613        buffer: Entity<Buffer>,
22614        ranges: Vec<Range<text::Anchor>>,
22615        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22616        cx: &mut App,
22617    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22618
22619    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22620
22621    fn document_highlights(
22622        &self,
22623        buffer: &Entity<Buffer>,
22624        position: text::Anchor,
22625        cx: &mut App,
22626    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22627
22628    fn definitions(
22629        &self,
22630        buffer: &Entity<Buffer>,
22631        position: text::Anchor,
22632        kind: GotoDefinitionKind,
22633        cx: &mut App,
22634    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22635
22636    fn range_for_rename(
22637        &self,
22638        buffer: &Entity<Buffer>,
22639        position: text::Anchor,
22640        cx: &mut App,
22641    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22642
22643    fn perform_rename(
22644        &self,
22645        buffer: &Entity<Buffer>,
22646        position: text::Anchor,
22647        new_name: String,
22648        cx: &mut App,
22649    ) -> Option<Task<Result<ProjectTransaction>>>;
22650}
22651
22652pub trait CompletionProvider {
22653    fn completions(
22654        &self,
22655        excerpt_id: ExcerptId,
22656        buffer: &Entity<Buffer>,
22657        buffer_position: text::Anchor,
22658        trigger: CompletionContext,
22659        window: &mut Window,
22660        cx: &mut Context<Editor>,
22661    ) -> Task<Result<Vec<CompletionResponse>>>;
22662
22663    fn resolve_completions(
22664        &self,
22665        _buffer: Entity<Buffer>,
22666        _completion_indices: Vec<usize>,
22667        _completions: Rc<RefCell<Box<[Completion]>>>,
22668        _cx: &mut Context<Editor>,
22669    ) -> Task<Result<bool>> {
22670        Task::ready(Ok(false))
22671    }
22672
22673    fn apply_additional_edits_for_completion(
22674        &self,
22675        _buffer: Entity<Buffer>,
22676        _completions: Rc<RefCell<Box<[Completion]>>>,
22677        _completion_index: usize,
22678        _push_to_history: bool,
22679        _cx: &mut Context<Editor>,
22680    ) -> Task<Result<Option<language::Transaction>>> {
22681        Task::ready(Ok(None))
22682    }
22683
22684    fn is_completion_trigger(
22685        &self,
22686        buffer: &Entity<Buffer>,
22687        position: language::Anchor,
22688        text: &str,
22689        trigger_in_words: bool,
22690        menu_is_open: bool,
22691        cx: &mut Context<Editor>,
22692    ) -> bool;
22693
22694    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22695
22696    fn sort_completions(&self) -> bool {
22697        true
22698    }
22699
22700    fn filter_completions(&self) -> bool {
22701        true
22702    }
22703}
22704
22705pub trait CodeActionProvider {
22706    fn id(&self) -> Arc<str>;
22707
22708    fn code_actions(
22709        &self,
22710        buffer: &Entity<Buffer>,
22711        range: Range<text::Anchor>,
22712        window: &mut Window,
22713        cx: &mut App,
22714    ) -> Task<Result<Vec<CodeAction>>>;
22715
22716    fn apply_code_action(
22717        &self,
22718        buffer_handle: Entity<Buffer>,
22719        action: CodeAction,
22720        excerpt_id: ExcerptId,
22721        push_to_history: bool,
22722        window: &mut Window,
22723        cx: &mut App,
22724    ) -> Task<Result<ProjectTransaction>>;
22725}
22726
22727impl CodeActionProvider for Entity<Project> {
22728    fn id(&self) -> Arc<str> {
22729        "project".into()
22730    }
22731
22732    fn code_actions(
22733        &self,
22734        buffer: &Entity<Buffer>,
22735        range: Range<text::Anchor>,
22736        _window: &mut Window,
22737        cx: &mut App,
22738    ) -> Task<Result<Vec<CodeAction>>> {
22739        self.update(cx, |project, cx| {
22740            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22741            let code_actions = project.code_actions(buffer, range, None, cx);
22742            cx.background_spawn(async move {
22743                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22744                Ok(code_lens_actions
22745                    .context("code lens fetch")?
22746                    .into_iter()
22747                    .flatten()
22748                    .chain(
22749                        code_actions
22750                            .context("code action fetch")?
22751                            .into_iter()
22752                            .flatten(),
22753                    )
22754                    .collect())
22755            })
22756        })
22757    }
22758
22759    fn apply_code_action(
22760        &self,
22761        buffer_handle: Entity<Buffer>,
22762        action: CodeAction,
22763        _excerpt_id: ExcerptId,
22764        push_to_history: bool,
22765        _window: &mut Window,
22766        cx: &mut App,
22767    ) -> Task<Result<ProjectTransaction>> {
22768        self.update(cx, |project, cx| {
22769            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22770        })
22771    }
22772}
22773
22774fn snippet_completions(
22775    project: &Project,
22776    buffer: &Entity<Buffer>,
22777    buffer_position: text::Anchor,
22778    cx: &mut App,
22779) -> Task<Result<CompletionResponse>> {
22780    let languages = buffer.read(cx).languages_at(buffer_position);
22781    let snippet_store = project.snippets().read(cx);
22782
22783    let scopes: Vec<_> = languages
22784        .iter()
22785        .filter_map(|language| {
22786            let language_name = language.lsp_id();
22787            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22788
22789            if snippets.is_empty() {
22790                None
22791            } else {
22792                Some((language.default_scope(), snippets))
22793            }
22794        })
22795        .collect();
22796
22797    if scopes.is_empty() {
22798        return Task::ready(Ok(CompletionResponse {
22799            completions: vec![],
22800            display_options: CompletionDisplayOptions::default(),
22801            is_incomplete: false,
22802        }));
22803    }
22804
22805    let snapshot = buffer.read(cx).text_snapshot();
22806    let executor = cx.background_executor().clone();
22807
22808    cx.background_spawn(async move {
22809        let mut is_incomplete = false;
22810        let mut completions: Vec<Completion> = Vec::new();
22811        for (scope, snippets) in scopes.into_iter() {
22812            let classifier =
22813                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22814
22815            const MAX_WORD_PREFIX_LEN: usize = 128;
22816            let last_word: String = snapshot
22817                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22818                .take(MAX_WORD_PREFIX_LEN)
22819                .take_while(|c| classifier.is_word(*c))
22820                .collect::<String>()
22821                .chars()
22822                .rev()
22823                .collect();
22824
22825            if last_word.is_empty() {
22826                return Ok(CompletionResponse {
22827                    completions: vec![],
22828                    display_options: CompletionDisplayOptions::default(),
22829                    is_incomplete: true,
22830                });
22831            }
22832
22833            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22834            let to_lsp = |point: &text::Anchor| {
22835                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22836                point_to_lsp(end)
22837            };
22838            let lsp_end = to_lsp(&buffer_position);
22839
22840            let candidates = snippets
22841                .iter()
22842                .enumerate()
22843                .flat_map(|(ix, snippet)| {
22844                    snippet
22845                        .prefix
22846                        .iter()
22847                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22848                })
22849                .collect::<Vec<StringMatchCandidate>>();
22850
22851            const MAX_RESULTS: usize = 100;
22852            let mut matches = fuzzy::match_strings(
22853                &candidates,
22854                &last_word,
22855                last_word.chars().any(|c| c.is_uppercase()),
22856                true,
22857                MAX_RESULTS,
22858                &Default::default(),
22859                executor.clone(),
22860            )
22861            .await;
22862
22863            if matches.len() >= MAX_RESULTS {
22864                is_incomplete = true;
22865            }
22866
22867            // Remove all candidates where the query's start does not match the start of any word in the candidate
22868            if let Some(query_start) = last_word.chars().next() {
22869                matches.retain(|string_match| {
22870                    split_words(&string_match.string).any(|word| {
22871                        // Check that the first codepoint of the word as lowercase matches the first
22872                        // codepoint of the query as lowercase
22873                        word.chars()
22874                            .flat_map(|codepoint| codepoint.to_lowercase())
22875                            .zip(query_start.to_lowercase())
22876                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22877                    })
22878                });
22879            }
22880
22881            let matched_strings = matches
22882                .into_iter()
22883                .map(|m| m.string)
22884                .collect::<HashSet<_>>();
22885
22886            completions.extend(snippets.iter().filter_map(|snippet| {
22887                let matching_prefix = snippet
22888                    .prefix
22889                    .iter()
22890                    .find(|prefix| matched_strings.contains(*prefix))?;
22891                let start = as_offset - last_word.len();
22892                let start = snapshot.anchor_before(start);
22893                let range = start..buffer_position;
22894                let lsp_start = to_lsp(&start);
22895                let lsp_range = lsp::Range {
22896                    start: lsp_start,
22897                    end: lsp_end,
22898                };
22899                Some(Completion {
22900                    replace_range: range,
22901                    new_text: snippet.body.clone(),
22902                    source: CompletionSource::Lsp {
22903                        insert_range: None,
22904                        server_id: LanguageServerId(usize::MAX),
22905                        resolved: true,
22906                        lsp_completion: Box::new(lsp::CompletionItem {
22907                            label: snippet.prefix.first().unwrap().clone(),
22908                            kind: Some(CompletionItemKind::SNIPPET),
22909                            label_details: snippet.description.as_ref().map(|description| {
22910                                lsp::CompletionItemLabelDetails {
22911                                    detail: Some(description.clone()),
22912                                    description: None,
22913                                }
22914                            }),
22915                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22916                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22917                                lsp::InsertReplaceEdit {
22918                                    new_text: snippet.body.clone(),
22919                                    insert: lsp_range,
22920                                    replace: lsp_range,
22921                                },
22922                            )),
22923                            filter_text: Some(snippet.body.clone()),
22924                            sort_text: Some(char::MAX.to_string()),
22925                            ..lsp::CompletionItem::default()
22926                        }),
22927                        lsp_defaults: None,
22928                    },
22929                    label: CodeLabel::plain(matching_prefix.clone(), None),
22930                    icon_path: None,
22931                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22932                        single_line: snippet.name.clone().into(),
22933                        plain_text: snippet
22934                            .description
22935                            .clone()
22936                            .map(|description| description.into()),
22937                    }),
22938                    insert_text_mode: None,
22939                    confirm: None,
22940                })
22941            }))
22942        }
22943
22944        Ok(CompletionResponse {
22945            completions,
22946            display_options: CompletionDisplayOptions::default(),
22947            is_incomplete,
22948        })
22949    })
22950}
22951
22952impl CompletionProvider for Entity<Project> {
22953    fn completions(
22954        &self,
22955        _excerpt_id: ExcerptId,
22956        buffer: &Entity<Buffer>,
22957        buffer_position: text::Anchor,
22958        options: CompletionContext,
22959        _window: &mut Window,
22960        cx: &mut Context<Editor>,
22961    ) -> Task<Result<Vec<CompletionResponse>>> {
22962        self.update(cx, |project, cx| {
22963            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22964            let project_completions = project.completions(buffer, buffer_position, options, cx);
22965            cx.background_spawn(async move {
22966                let mut responses = project_completions.await?;
22967                let snippets = snippets.await?;
22968                if !snippets.completions.is_empty() {
22969                    responses.push(snippets);
22970                }
22971                Ok(responses)
22972            })
22973        })
22974    }
22975
22976    fn resolve_completions(
22977        &self,
22978        buffer: Entity<Buffer>,
22979        completion_indices: Vec<usize>,
22980        completions: Rc<RefCell<Box<[Completion]>>>,
22981        cx: &mut Context<Editor>,
22982    ) -> Task<Result<bool>> {
22983        self.update(cx, |project, cx| {
22984            project.lsp_store().update(cx, |lsp_store, cx| {
22985                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22986            })
22987        })
22988    }
22989
22990    fn apply_additional_edits_for_completion(
22991        &self,
22992        buffer: Entity<Buffer>,
22993        completions: Rc<RefCell<Box<[Completion]>>>,
22994        completion_index: usize,
22995        push_to_history: bool,
22996        cx: &mut Context<Editor>,
22997    ) -> Task<Result<Option<language::Transaction>>> {
22998        self.update(cx, |project, cx| {
22999            project.lsp_store().update(cx, |lsp_store, cx| {
23000                lsp_store.apply_additional_edits_for_completion(
23001                    buffer,
23002                    completions,
23003                    completion_index,
23004                    push_to_history,
23005                    cx,
23006                )
23007            })
23008        })
23009    }
23010
23011    fn is_completion_trigger(
23012        &self,
23013        buffer: &Entity<Buffer>,
23014        position: language::Anchor,
23015        text: &str,
23016        trigger_in_words: bool,
23017        menu_is_open: bool,
23018        cx: &mut Context<Editor>,
23019    ) -> bool {
23020        let mut chars = text.chars();
23021        let char = if let Some(char) = chars.next() {
23022            char
23023        } else {
23024            return false;
23025        };
23026        if chars.next().is_some() {
23027            return false;
23028        }
23029
23030        let buffer = buffer.read(cx);
23031        let snapshot = buffer.snapshot();
23032        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23033            return false;
23034        }
23035        let classifier = snapshot
23036            .char_classifier_at(position)
23037            .scope_context(Some(CharScopeContext::Completion));
23038        if trigger_in_words && classifier.is_word(char) {
23039            return true;
23040        }
23041
23042        buffer.completion_triggers().contains(text)
23043    }
23044}
23045
23046impl SemanticsProvider for Entity<Project> {
23047    fn hover(
23048        &self,
23049        buffer: &Entity<Buffer>,
23050        position: text::Anchor,
23051        cx: &mut App,
23052    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23053        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23054    }
23055
23056    fn document_highlights(
23057        &self,
23058        buffer: &Entity<Buffer>,
23059        position: text::Anchor,
23060        cx: &mut App,
23061    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23062        Some(self.update(cx, |project, cx| {
23063            project.document_highlights(buffer, position, cx)
23064        }))
23065    }
23066
23067    fn definitions(
23068        &self,
23069        buffer: &Entity<Buffer>,
23070        position: text::Anchor,
23071        kind: GotoDefinitionKind,
23072        cx: &mut App,
23073    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23074        Some(self.update(cx, |project, cx| match kind {
23075            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23076            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23077            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23078            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23079        }))
23080    }
23081
23082    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23083        self.update(cx, |project, cx| {
23084            if project
23085                .active_debug_session(cx)
23086                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23087            {
23088                return true;
23089            }
23090
23091            buffer.update(cx, |buffer, cx| {
23092                project.any_language_server_supports_inlay_hints(buffer, cx)
23093            })
23094        })
23095    }
23096
23097    fn inline_values(
23098        &self,
23099        buffer_handle: Entity<Buffer>,
23100        range: Range<text::Anchor>,
23101        cx: &mut App,
23102    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23103        self.update(cx, |project, cx| {
23104            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23105
23106            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23107        })
23108    }
23109
23110    fn applicable_inlay_chunks(
23111        &self,
23112        buffer_id: BufferId,
23113        ranges: &[Range<text::Anchor>],
23114        cx: &App,
23115    ) -> Vec<Range<BufferRow>> {
23116        self.read(cx)
23117            .lsp_store()
23118            .read(cx)
23119            .applicable_inlay_chunks(buffer_id, ranges)
23120    }
23121
23122    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23123        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23124            lsp_store.invalidate_inlay_hints(for_buffers)
23125        });
23126    }
23127
23128    fn inlay_hints(
23129        &self,
23130        invalidate: InvalidationStrategy,
23131        buffer: Entity<Buffer>,
23132        ranges: Vec<Range<text::Anchor>>,
23133        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23134        cx: &mut App,
23135    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23136        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23137            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23138        }))
23139    }
23140
23141    fn range_for_rename(
23142        &self,
23143        buffer: &Entity<Buffer>,
23144        position: text::Anchor,
23145        cx: &mut App,
23146    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23147        Some(self.update(cx, |project, cx| {
23148            let buffer = buffer.clone();
23149            let task = project.prepare_rename(buffer.clone(), position, cx);
23150            cx.spawn(async move |_, cx| {
23151                Ok(match task.await? {
23152                    PrepareRenameResponse::Success(range) => Some(range),
23153                    PrepareRenameResponse::InvalidPosition => None,
23154                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23155                        // Fallback on using TreeSitter info to determine identifier range
23156                        buffer.read_with(cx, |buffer, _| {
23157                            let snapshot = buffer.snapshot();
23158                            let (range, kind) = snapshot.surrounding_word(position, None);
23159                            if kind != Some(CharKind::Word) {
23160                                return None;
23161                            }
23162                            Some(
23163                                snapshot.anchor_before(range.start)
23164                                    ..snapshot.anchor_after(range.end),
23165                            )
23166                        })?
23167                    }
23168                })
23169            })
23170        }))
23171    }
23172
23173    fn perform_rename(
23174        &self,
23175        buffer: &Entity<Buffer>,
23176        position: text::Anchor,
23177        new_name: String,
23178        cx: &mut App,
23179    ) -> Option<Task<Result<ProjectTransaction>>> {
23180        Some(self.update(cx, |project, cx| {
23181            project.perform_rename(buffer.clone(), position, new_name, cx)
23182        }))
23183    }
23184}
23185
23186fn consume_contiguous_rows(
23187    contiguous_row_selections: &mut Vec<Selection<Point>>,
23188    selection: &Selection<Point>,
23189    display_map: &DisplaySnapshot,
23190    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23191) -> (MultiBufferRow, MultiBufferRow) {
23192    contiguous_row_selections.push(selection.clone());
23193    let start_row = starting_row(selection, display_map);
23194    let mut end_row = ending_row(selection, display_map);
23195
23196    while let Some(next_selection) = selections.peek() {
23197        if next_selection.start.row <= end_row.0 {
23198            end_row = ending_row(next_selection, display_map);
23199            contiguous_row_selections.push(selections.next().unwrap().clone());
23200        } else {
23201            break;
23202        }
23203    }
23204    (start_row, end_row)
23205}
23206
23207fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23208    if selection.start.column > 0 {
23209        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23210    } else {
23211        MultiBufferRow(selection.start.row)
23212    }
23213}
23214
23215fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23216    if next_selection.end.column > 0 || next_selection.is_empty() {
23217        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23218    } else {
23219        MultiBufferRow(next_selection.end.row)
23220    }
23221}
23222
23223impl EditorSnapshot {
23224    pub fn remote_selections_in_range<'a>(
23225        &'a self,
23226        range: &'a Range<Anchor>,
23227        collaboration_hub: &dyn CollaborationHub,
23228        cx: &'a App,
23229    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23230        let participant_names = collaboration_hub.user_names(cx);
23231        let participant_indices = collaboration_hub.user_participant_indices(cx);
23232        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23233        let collaborators_by_replica_id = collaborators_by_peer_id
23234            .values()
23235            .map(|collaborator| (collaborator.replica_id, collaborator))
23236            .collect::<HashMap<_, _>>();
23237        self.buffer_snapshot()
23238            .selections_in_range(range, false)
23239            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23240                if replica_id == ReplicaId::AGENT {
23241                    Some(RemoteSelection {
23242                        replica_id,
23243                        selection,
23244                        cursor_shape,
23245                        line_mode,
23246                        collaborator_id: CollaboratorId::Agent,
23247                        user_name: Some("Agent".into()),
23248                        color: cx.theme().players().agent(),
23249                    })
23250                } else {
23251                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23252                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23253                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23254                    Some(RemoteSelection {
23255                        replica_id,
23256                        selection,
23257                        cursor_shape,
23258                        line_mode,
23259                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23260                        user_name,
23261                        color: if let Some(index) = participant_index {
23262                            cx.theme().players().color_for_participant(index.0)
23263                        } else {
23264                            cx.theme().players().absent()
23265                        },
23266                    })
23267                }
23268            })
23269    }
23270
23271    pub fn hunks_for_ranges(
23272        &self,
23273        ranges: impl IntoIterator<Item = Range<Point>>,
23274    ) -> Vec<MultiBufferDiffHunk> {
23275        let mut hunks = Vec::new();
23276        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23277            HashMap::default();
23278        for query_range in ranges {
23279            let query_rows =
23280                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23281            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23282                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23283            ) {
23284                // Include deleted hunks that are adjacent to the query range, because
23285                // otherwise they would be missed.
23286                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23287                if hunk.status().is_deleted() {
23288                    intersects_range |= hunk.row_range.start == query_rows.end;
23289                    intersects_range |= hunk.row_range.end == query_rows.start;
23290                }
23291                if intersects_range {
23292                    if !processed_buffer_rows
23293                        .entry(hunk.buffer_id)
23294                        .or_default()
23295                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23296                    {
23297                        continue;
23298                    }
23299                    hunks.push(hunk);
23300                }
23301            }
23302        }
23303
23304        hunks
23305    }
23306
23307    fn display_diff_hunks_for_rows<'a>(
23308        &'a self,
23309        display_rows: Range<DisplayRow>,
23310        folded_buffers: &'a HashSet<BufferId>,
23311    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23312        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23313        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23314
23315        self.buffer_snapshot()
23316            .diff_hunks_in_range(buffer_start..buffer_end)
23317            .filter_map(|hunk| {
23318                if folded_buffers.contains(&hunk.buffer_id) {
23319                    return None;
23320                }
23321
23322                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23323                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23324
23325                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23326                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23327
23328                let display_hunk = if hunk_display_start.column() != 0 {
23329                    DisplayDiffHunk::Folded {
23330                        display_row: hunk_display_start.row(),
23331                    }
23332                } else {
23333                    let mut end_row = hunk_display_end.row();
23334                    if hunk_display_end.column() > 0 {
23335                        end_row.0 += 1;
23336                    }
23337                    let is_created_file = hunk.is_created_file();
23338                    DisplayDiffHunk::Unfolded {
23339                        status: hunk.status(),
23340                        diff_base_byte_range: hunk.diff_base_byte_range,
23341                        display_row_range: hunk_display_start.row()..end_row,
23342                        multi_buffer_range: Anchor::range_in_buffer(
23343                            hunk.excerpt_id,
23344                            hunk.buffer_id,
23345                            hunk.buffer_range,
23346                        ),
23347                        is_created_file,
23348                    }
23349                };
23350
23351                Some(display_hunk)
23352            })
23353    }
23354
23355    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23356        self.display_snapshot
23357            .buffer_snapshot()
23358            .language_at(position)
23359    }
23360
23361    pub fn is_focused(&self) -> bool {
23362        self.is_focused
23363    }
23364
23365    pub fn placeholder_text(&self) -> Option<String> {
23366        self.placeholder_display_snapshot
23367            .as_ref()
23368            .map(|display_map| display_map.text())
23369    }
23370
23371    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23372        self.scroll_anchor.scroll_position(&self.display_snapshot)
23373    }
23374
23375    fn gutter_dimensions(
23376        &self,
23377        font_id: FontId,
23378        font_size: Pixels,
23379        max_line_number_width: Pixels,
23380        cx: &App,
23381    ) -> Option<GutterDimensions> {
23382        if !self.show_gutter {
23383            return None;
23384        }
23385
23386        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23387        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23388
23389        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23390            matches!(
23391                ProjectSettings::get_global(cx).git.git_gutter,
23392                GitGutterSetting::TrackedFiles
23393            )
23394        });
23395        let gutter_settings = EditorSettings::get_global(cx).gutter;
23396        let show_line_numbers = self
23397            .show_line_numbers
23398            .unwrap_or(gutter_settings.line_numbers);
23399        let line_gutter_width = if show_line_numbers {
23400            // Avoid flicker-like gutter resizes when the line number gains another digit by
23401            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23402            let min_width_for_number_on_gutter =
23403                ch_advance * gutter_settings.min_line_number_digits as f32;
23404            max_line_number_width.max(min_width_for_number_on_gutter)
23405        } else {
23406            0.0.into()
23407        };
23408
23409        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23410        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23411
23412        let git_blame_entries_width =
23413            self.git_blame_gutter_max_author_length
23414                .map(|max_author_length| {
23415                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23416                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23417
23418                    /// The number of characters to dedicate to gaps and margins.
23419                    const SPACING_WIDTH: usize = 4;
23420
23421                    let max_char_count = max_author_length.min(renderer.max_author_length())
23422                        + ::git::SHORT_SHA_LENGTH
23423                        + MAX_RELATIVE_TIMESTAMP.len()
23424                        + SPACING_WIDTH;
23425
23426                    ch_advance * max_char_count
23427                });
23428
23429        let is_singleton = self.buffer_snapshot().is_singleton();
23430
23431        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23432        left_padding += if !is_singleton {
23433            ch_width * 4.0
23434        } else if show_runnables || show_breakpoints {
23435            ch_width * 3.0
23436        } else if show_git_gutter && show_line_numbers {
23437            ch_width * 2.0
23438        } else if show_git_gutter || show_line_numbers {
23439            ch_width
23440        } else {
23441            px(0.)
23442        };
23443
23444        let shows_folds = is_singleton && gutter_settings.folds;
23445
23446        let right_padding = if shows_folds && show_line_numbers {
23447            ch_width * 4.0
23448        } else if shows_folds || (!is_singleton && show_line_numbers) {
23449            ch_width * 3.0
23450        } else if show_line_numbers {
23451            ch_width
23452        } else {
23453            px(0.)
23454        };
23455
23456        Some(GutterDimensions {
23457            left_padding,
23458            right_padding,
23459            width: line_gutter_width + left_padding + right_padding,
23460            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23461            git_blame_entries_width,
23462        })
23463    }
23464
23465    pub fn render_crease_toggle(
23466        &self,
23467        buffer_row: MultiBufferRow,
23468        row_contains_cursor: bool,
23469        editor: Entity<Editor>,
23470        window: &mut Window,
23471        cx: &mut App,
23472    ) -> Option<AnyElement> {
23473        let folded = self.is_line_folded(buffer_row);
23474        let mut is_foldable = false;
23475
23476        if let Some(crease) = self
23477            .crease_snapshot
23478            .query_row(buffer_row, self.buffer_snapshot())
23479        {
23480            is_foldable = true;
23481            match crease {
23482                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23483                    if let Some(render_toggle) = render_toggle {
23484                        let toggle_callback =
23485                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23486                                if folded {
23487                                    editor.update(cx, |editor, cx| {
23488                                        editor.fold_at(buffer_row, window, cx)
23489                                    });
23490                                } else {
23491                                    editor.update(cx, |editor, cx| {
23492                                        editor.unfold_at(buffer_row, window, cx)
23493                                    });
23494                                }
23495                            });
23496                        return Some((render_toggle)(
23497                            buffer_row,
23498                            folded,
23499                            toggle_callback,
23500                            window,
23501                            cx,
23502                        ));
23503                    }
23504                }
23505            }
23506        }
23507
23508        is_foldable |= self.starts_indent(buffer_row);
23509
23510        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23511            Some(
23512                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23513                    .toggle_state(folded)
23514                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23515                        if folded {
23516                            this.unfold_at(buffer_row, window, cx);
23517                        } else {
23518                            this.fold_at(buffer_row, window, cx);
23519                        }
23520                    }))
23521                    .into_any_element(),
23522            )
23523        } else {
23524            None
23525        }
23526    }
23527
23528    pub fn render_crease_trailer(
23529        &self,
23530        buffer_row: MultiBufferRow,
23531        window: &mut Window,
23532        cx: &mut App,
23533    ) -> Option<AnyElement> {
23534        let folded = self.is_line_folded(buffer_row);
23535        if let Crease::Inline { render_trailer, .. } = self
23536            .crease_snapshot
23537            .query_row(buffer_row, self.buffer_snapshot())?
23538        {
23539            let render_trailer = render_trailer.as_ref()?;
23540            Some(render_trailer(buffer_row, folded, window, cx))
23541        } else {
23542            None
23543        }
23544    }
23545}
23546
23547impl Deref for EditorSnapshot {
23548    type Target = DisplaySnapshot;
23549
23550    fn deref(&self) -> &Self::Target {
23551        &self.display_snapshot
23552    }
23553}
23554
23555#[derive(Clone, Debug, PartialEq, Eq)]
23556pub enum EditorEvent {
23557    InputIgnored {
23558        text: Arc<str>,
23559    },
23560    InputHandled {
23561        utf16_range_to_replace: Option<Range<isize>>,
23562        text: Arc<str>,
23563    },
23564    ExcerptsAdded {
23565        buffer: Entity<Buffer>,
23566        predecessor: ExcerptId,
23567        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23568    },
23569    ExcerptsRemoved {
23570        ids: Vec<ExcerptId>,
23571        removed_buffer_ids: Vec<BufferId>,
23572    },
23573    BufferFoldToggled {
23574        ids: Vec<ExcerptId>,
23575        folded: bool,
23576    },
23577    ExcerptsEdited {
23578        ids: Vec<ExcerptId>,
23579    },
23580    ExcerptsExpanded {
23581        ids: Vec<ExcerptId>,
23582    },
23583    BufferEdited,
23584    Edited {
23585        transaction_id: clock::Lamport,
23586    },
23587    Reparsed(BufferId),
23588    Focused,
23589    FocusedIn,
23590    Blurred,
23591    DirtyChanged,
23592    Saved,
23593    TitleChanged,
23594    SelectionsChanged {
23595        local: bool,
23596    },
23597    ScrollPositionChanged {
23598        local: bool,
23599        autoscroll: bool,
23600    },
23601    TransactionUndone {
23602        transaction_id: clock::Lamport,
23603    },
23604    TransactionBegun {
23605        transaction_id: clock::Lamport,
23606    },
23607    CursorShapeChanged,
23608    BreadcrumbsChanged,
23609    PushedToNavHistory {
23610        anchor: Anchor,
23611        is_deactivate: bool,
23612    },
23613}
23614
23615impl EventEmitter<EditorEvent> for Editor {}
23616
23617impl Focusable for Editor {
23618    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23619        self.focus_handle.clone()
23620    }
23621}
23622
23623impl Render for Editor {
23624    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23625        let settings = ThemeSettings::get_global(cx);
23626
23627        let mut text_style = match self.mode {
23628            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23629                color: cx.theme().colors().editor_foreground,
23630                font_family: settings.ui_font.family.clone(),
23631                font_features: settings.ui_font.features.clone(),
23632                font_fallbacks: settings.ui_font.fallbacks.clone(),
23633                font_size: rems(0.875).into(),
23634                font_weight: settings.ui_font.weight,
23635                line_height: relative(settings.buffer_line_height.value()),
23636                ..Default::default()
23637            },
23638            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23639                color: cx.theme().colors().editor_foreground,
23640                font_family: settings.buffer_font.family.clone(),
23641                font_features: settings.buffer_font.features.clone(),
23642                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23643                font_size: settings.buffer_font_size(cx).into(),
23644                font_weight: settings.buffer_font.weight,
23645                line_height: relative(settings.buffer_line_height.value()),
23646                ..Default::default()
23647            },
23648        };
23649        if let Some(text_style_refinement) = &self.text_style_refinement {
23650            text_style.refine(text_style_refinement)
23651        }
23652
23653        let background = match self.mode {
23654            EditorMode::SingleLine => cx.theme().system().transparent,
23655            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23656            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23657            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23658        };
23659
23660        EditorElement::new(
23661            &cx.entity(),
23662            EditorStyle {
23663                background,
23664                border: cx.theme().colors().border,
23665                local_player: cx.theme().players().local(),
23666                text: text_style,
23667                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23668                syntax: cx.theme().syntax().clone(),
23669                status: cx.theme().status().clone(),
23670                inlay_hints_style: make_inlay_hints_style(cx),
23671                edit_prediction_styles: make_suggestion_styles(cx),
23672                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23673                show_underlines: self.diagnostics_enabled(),
23674            },
23675        )
23676    }
23677}
23678
23679impl EntityInputHandler for Editor {
23680    fn text_for_range(
23681        &mut self,
23682        range_utf16: Range<usize>,
23683        adjusted_range: &mut Option<Range<usize>>,
23684        _: &mut Window,
23685        cx: &mut Context<Self>,
23686    ) -> Option<String> {
23687        let snapshot = self.buffer.read(cx).read(cx);
23688        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23689        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23690        if (start.0..end.0) != range_utf16 {
23691            adjusted_range.replace(start.0..end.0);
23692        }
23693        Some(snapshot.text_for_range(start..end).collect())
23694    }
23695
23696    fn selected_text_range(
23697        &mut self,
23698        ignore_disabled_input: bool,
23699        _: &mut Window,
23700        cx: &mut Context<Self>,
23701    ) -> Option<UTF16Selection> {
23702        // Prevent the IME menu from appearing when holding down an alphabetic key
23703        // while input is disabled.
23704        if !ignore_disabled_input && !self.input_enabled {
23705            return None;
23706        }
23707
23708        let selection = self
23709            .selections
23710            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
23711        let range = selection.range();
23712
23713        Some(UTF16Selection {
23714            range: range.start.0..range.end.0,
23715            reversed: selection.reversed,
23716        })
23717    }
23718
23719    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23720        let snapshot = self.buffer.read(cx).read(cx);
23721        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23722        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23723    }
23724
23725    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23726        self.clear_highlights::<InputComposition>(cx);
23727        self.ime_transaction.take();
23728    }
23729
23730    fn replace_text_in_range(
23731        &mut self,
23732        range_utf16: Option<Range<usize>>,
23733        text: &str,
23734        window: &mut Window,
23735        cx: &mut Context<Self>,
23736    ) {
23737        if !self.input_enabled {
23738            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23739            return;
23740        }
23741
23742        self.transact(window, cx, |this, window, cx| {
23743            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23744                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23745                Some(this.selection_replacement_ranges(range_utf16, cx))
23746            } else {
23747                this.marked_text_ranges(cx)
23748            };
23749
23750            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23751                let newest_selection_id = this.selections.newest_anchor().id;
23752                this.selections
23753                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23754                    .iter()
23755                    .zip(ranges_to_replace.iter())
23756                    .find_map(|(selection, range)| {
23757                        if selection.id == newest_selection_id {
23758                            Some(
23759                                (range.start.0 as isize - selection.head().0 as isize)
23760                                    ..(range.end.0 as isize - selection.head().0 as isize),
23761                            )
23762                        } else {
23763                            None
23764                        }
23765                    })
23766            });
23767
23768            cx.emit(EditorEvent::InputHandled {
23769                utf16_range_to_replace: range_to_replace,
23770                text: text.into(),
23771            });
23772
23773            if let Some(new_selected_ranges) = new_selected_ranges {
23774                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23775                    selections.select_ranges(new_selected_ranges)
23776                });
23777                this.backspace(&Default::default(), window, cx);
23778            }
23779
23780            this.handle_input(text, window, cx);
23781        });
23782
23783        if let Some(transaction) = self.ime_transaction {
23784            self.buffer.update(cx, |buffer, cx| {
23785                buffer.group_until_transaction(transaction, cx);
23786            });
23787        }
23788
23789        self.unmark_text(window, cx);
23790    }
23791
23792    fn replace_and_mark_text_in_range(
23793        &mut self,
23794        range_utf16: Option<Range<usize>>,
23795        text: &str,
23796        new_selected_range_utf16: Option<Range<usize>>,
23797        window: &mut Window,
23798        cx: &mut Context<Self>,
23799    ) {
23800        if !self.input_enabled {
23801            return;
23802        }
23803
23804        let transaction = self.transact(window, cx, |this, window, cx| {
23805            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23806                let snapshot = this.buffer.read(cx).read(cx);
23807                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23808                    for marked_range in &mut marked_ranges {
23809                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23810                        marked_range.start.0 += relative_range_utf16.start;
23811                        marked_range.start =
23812                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23813                        marked_range.end =
23814                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23815                    }
23816                }
23817                Some(marked_ranges)
23818            } else if let Some(range_utf16) = range_utf16 {
23819                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23820                Some(this.selection_replacement_ranges(range_utf16, cx))
23821            } else {
23822                None
23823            };
23824
23825            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23826                let newest_selection_id = this.selections.newest_anchor().id;
23827                this.selections
23828                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23829                    .iter()
23830                    .zip(ranges_to_replace.iter())
23831                    .find_map(|(selection, range)| {
23832                        if selection.id == newest_selection_id {
23833                            Some(
23834                                (range.start.0 as isize - selection.head().0 as isize)
23835                                    ..(range.end.0 as isize - selection.head().0 as isize),
23836                            )
23837                        } else {
23838                            None
23839                        }
23840                    })
23841            });
23842
23843            cx.emit(EditorEvent::InputHandled {
23844                utf16_range_to_replace: range_to_replace,
23845                text: text.into(),
23846            });
23847
23848            if let Some(ranges) = ranges_to_replace {
23849                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23850                    s.select_ranges(ranges)
23851                });
23852            }
23853
23854            let marked_ranges = {
23855                let snapshot = this.buffer.read(cx).read(cx);
23856                this.selections
23857                    .disjoint_anchors_arc()
23858                    .iter()
23859                    .map(|selection| {
23860                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23861                    })
23862                    .collect::<Vec<_>>()
23863            };
23864
23865            if text.is_empty() {
23866                this.unmark_text(window, cx);
23867            } else {
23868                this.highlight_text::<InputComposition>(
23869                    marked_ranges.clone(),
23870                    HighlightStyle {
23871                        underline: Some(UnderlineStyle {
23872                            thickness: px(1.),
23873                            color: None,
23874                            wavy: false,
23875                        }),
23876                        ..Default::default()
23877                    },
23878                    cx,
23879                );
23880            }
23881
23882            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23883            let use_autoclose = this.use_autoclose;
23884            let use_auto_surround = this.use_auto_surround;
23885            this.set_use_autoclose(false);
23886            this.set_use_auto_surround(false);
23887            this.handle_input(text, window, cx);
23888            this.set_use_autoclose(use_autoclose);
23889            this.set_use_auto_surround(use_auto_surround);
23890
23891            if let Some(new_selected_range) = new_selected_range_utf16 {
23892                let snapshot = this.buffer.read(cx).read(cx);
23893                let new_selected_ranges = marked_ranges
23894                    .into_iter()
23895                    .map(|marked_range| {
23896                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23897                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23898                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23899                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23900                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23901                    })
23902                    .collect::<Vec<_>>();
23903
23904                drop(snapshot);
23905                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23906                    selections.select_ranges(new_selected_ranges)
23907                });
23908            }
23909        });
23910
23911        self.ime_transaction = self.ime_transaction.or(transaction);
23912        if let Some(transaction) = self.ime_transaction {
23913            self.buffer.update(cx, |buffer, cx| {
23914                buffer.group_until_transaction(transaction, cx);
23915            });
23916        }
23917
23918        if self.text_highlights::<InputComposition>(cx).is_none() {
23919            self.ime_transaction.take();
23920        }
23921    }
23922
23923    fn bounds_for_range(
23924        &mut self,
23925        range_utf16: Range<usize>,
23926        element_bounds: gpui::Bounds<Pixels>,
23927        window: &mut Window,
23928        cx: &mut Context<Self>,
23929    ) -> Option<gpui::Bounds<Pixels>> {
23930        let text_layout_details = self.text_layout_details(window);
23931        let CharacterDimensions {
23932            em_width,
23933            em_advance,
23934            line_height,
23935        } = self.character_dimensions(window);
23936
23937        let snapshot = self.snapshot(window, cx);
23938        let scroll_position = snapshot.scroll_position();
23939        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
23940
23941        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23942        let x = Pixels::from(
23943            ScrollOffset::from(
23944                snapshot.x_for_display_point(start, &text_layout_details)
23945                    + self.gutter_dimensions.full_width(),
23946            ) - scroll_left,
23947        );
23948        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
23949
23950        Some(Bounds {
23951            origin: element_bounds.origin + point(x, y),
23952            size: size(em_width, line_height),
23953        })
23954    }
23955
23956    fn character_index_for_point(
23957        &mut self,
23958        point: gpui::Point<Pixels>,
23959        _window: &mut Window,
23960        _cx: &mut Context<Self>,
23961    ) -> Option<usize> {
23962        let position_map = self.last_position_map.as_ref()?;
23963        if !position_map.text_hitbox.contains(&point) {
23964            return None;
23965        }
23966        let display_point = position_map.point_for_position(point).previous_valid;
23967        let anchor = position_map
23968            .snapshot
23969            .display_point_to_anchor(display_point, Bias::Left);
23970        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
23971        Some(utf16_offset.0)
23972    }
23973}
23974
23975trait SelectionExt {
23976    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23977    fn spanned_rows(
23978        &self,
23979        include_end_if_at_line_start: bool,
23980        map: &DisplaySnapshot,
23981    ) -> Range<MultiBufferRow>;
23982}
23983
23984impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23985    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23986        let start = self
23987            .start
23988            .to_point(map.buffer_snapshot())
23989            .to_display_point(map);
23990        let end = self
23991            .end
23992            .to_point(map.buffer_snapshot())
23993            .to_display_point(map);
23994        if self.reversed {
23995            end..start
23996        } else {
23997            start..end
23998        }
23999    }
24000
24001    fn spanned_rows(
24002        &self,
24003        include_end_if_at_line_start: bool,
24004        map: &DisplaySnapshot,
24005    ) -> Range<MultiBufferRow> {
24006        let start = self.start.to_point(map.buffer_snapshot());
24007        let mut end = self.end.to_point(map.buffer_snapshot());
24008        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24009            end.row -= 1;
24010        }
24011
24012        let buffer_start = map.prev_line_boundary(start).0;
24013        let buffer_end = map.next_line_boundary(end).0;
24014        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24015    }
24016}
24017
24018impl<T: InvalidationRegion> InvalidationStack<T> {
24019    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24020    where
24021        S: Clone + ToOffset,
24022    {
24023        while let Some(region) = self.last() {
24024            let all_selections_inside_invalidation_ranges =
24025                if selections.len() == region.ranges().len() {
24026                    selections
24027                        .iter()
24028                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24029                        .all(|(selection, invalidation_range)| {
24030                            let head = selection.head().to_offset(buffer);
24031                            invalidation_range.start <= head && invalidation_range.end >= head
24032                        })
24033                } else {
24034                    false
24035                };
24036
24037            if all_selections_inside_invalidation_ranges {
24038                break;
24039            } else {
24040                self.pop();
24041            }
24042        }
24043    }
24044}
24045
24046impl<T> Default for InvalidationStack<T> {
24047    fn default() -> Self {
24048        Self(Default::default())
24049    }
24050}
24051
24052impl<T> Deref for InvalidationStack<T> {
24053    type Target = Vec<T>;
24054
24055    fn deref(&self) -> &Self::Target {
24056        &self.0
24057    }
24058}
24059
24060impl<T> DerefMut for InvalidationStack<T> {
24061    fn deref_mut(&mut self) -> &mut Self::Target {
24062        &mut self.0
24063    }
24064}
24065
24066impl InvalidationRegion for SnippetState {
24067    fn ranges(&self) -> &[Range<Anchor>] {
24068        &self.ranges[self.active_index]
24069    }
24070}
24071
24072fn edit_prediction_edit_text(
24073    current_snapshot: &BufferSnapshot,
24074    edits: &[(Range<Anchor>, String)],
24075    edit_preview: &EditPreview,
24076    include_deletions: bool,
24077    cx: &App,
24078) -> HighlightedText {
24079    let edits = edits
24080        .iter()
24081        .map(|(anchor, text)| {
24082            (
24083                anchor.start.text_anchor..anchor.end.text_anchor,
24084                text.clone(),
24085            )
24086        })
24087        .collect::<Vec<_>>();
24088
24089    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24090}
24091
24092fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24093    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24094    // Just show the raw edit text with basic styling
24095    let mut text = String::new();
24096    let mut highlights = Vec::new();
24097
24098    let insertion_highlight_style = HighlightStyle {
24099        color: Some(cx.theme().colors().text),
24100        ..Default::default()
24101    };
24102
24103    for (_, edit_text) in edits {
24104        let start_offset = text.len();
24105        text.push_str(edit_text);
24106        let end_offset = text.len();
24107
24108        if start_offset < end_offset {
24109            highlights.push((start_offset..end_offset, insertion_highlight_style));
24110        }
24111    }
24112
24113    HighlightedText {
24114        text: text.into(),
24115        highlights,
24116    }
24117}
24118
24119pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24120    match severity {
24121        lsp::DiagnosticSeverity::ERROR => colors.error,
24122        lsp::DiagnosticSeverity::WARNING => colors.warning,
24123        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24124        lsp::DiagnosticSeverity::HINT => colors.info,
24125        _ => colors.ignored,
24126    }
24127}
24128
24129pub fn styled_runs_for_code_label<'a>(
24130    label: &'a CodeLabel,
24131    syntax_theme: &'a theme::SyntaxTheme,
24132) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24133    let fade_out = HighlightStyle {
24134        fade_out: Some(0.35),
24135        ..Default::default()
24136    };
24137
24138    let mut prev_end = label.filter_range.end;
24139    label
24140        .runs
24141        .iter()
24142        .enumerate()
24143        .flat_map(move |(ix, (range, highlight_id))| {
24144            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24145                style
24146            } else {
24147                return Default::default();
24148            };
24149            let muted_style = style.highlight(fade_out);
24150
24151            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24152            if range.start >= label.filter_range.end {
24153                if range.start > prev_end {
24154                    runs.push((prev_end..range.start, fade_out));
24155                }
24156                runs.push((range.clone(), muted_style));
24157            } else if range.end <= label.filter_range.end {
24158                runs.push((range.clone(), style));
24159            } else {
24160                runs.push((range.start..label.filter_range.end, style));
24161                runs.push((label.filter_range.end..range.end, muted_style));
24162            }
24163            prev_end = cmp::max(prev_end, range.end);
24164
24165            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24166                runs.push((prev_end..label.text.len(), fade_out));
24167            }
24168
24169            runs
24170        })
24171}
24172
24173pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24174    let mut prev_index = 0;
24175    let mut prev_codepoint: Option<char> = None;
24176    text.char_indices()
24177        .chain([(text.len(), '\0')])
24178        .filter_map(move |(index, codepoint)| {
24179            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24180            let is_boundary = index == text.len()
24181                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24182                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24183            if is_boundary {
24184                let chunk = &text[prev_index..index];
24185                prev_index = index;
24186                Some(chunk)
24187            } else {
24188                None
24189            }
24190        })
24191}
24192
24193pub trait RangeToAnchorExt: Sized {
24194    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24195
24196    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24197        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24198        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24199    }
24200}
24201
24202impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24203    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24204        let start_offset = self.start.to_offset(snapshot);
24205        let end_offset = self.end.to_offset(snapshot);
24206        if start_offset == end_offset {
24207            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24208        } else {
24209            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24210        }
24211    }
24212}
24213
24214pub trait RowExt {
24215    fn as_f64(&self) -> f64;
24216
24217    fn next_row(&self) -> Self;
24218
24219    fn previous_row(&self) -> Self;
24220
24221    fn minus(&self, other: Self) -> u32;
24222}
24223
24224impl RowExt for DisplayRow {
24225    fn as_f64(&self) -> f64 {
24226        self.0 as _
24227    }
24228
24229    fn next_row(&self) -> Self {
24230        Self(self.0 + 1)
24231    }
24232
24233    fn previous_row(&self) -> Self {
24234        Self(self.0.saturating_sub(1))
24235    }
24236
24237    fn minus(&self, other: Self) -> u32 {
24238        self.0 - other.0
24239    }
24240}
24241
24242impl RowExt for MultiBufferRow {
24243    fn as_f64(&self) -> f64 {
24244        self.0 as _
24245    }
24246
24247    fn next_row(&self) -> Self {
24248        Self(self.0 + 1)
24249    }
24250
24251    fn previous_row(&self) -> Self {
24252        Self(self.0.saturating_sub(1))
24253    }
24254
24255    fn minus(&self, other: Self) -> u32 {
24256        self.0 - other.0
24257    }
24258}
24259
24260trait RowRangeExt {
24261    type Row;
24262
24263    fn len(&self) -> usize;
24264
24265    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24266}
24267
24268impl RowRangeExt for Range<MultiBufferRow> {
24269    type Row = MultiBufferRow;
24270
24271    fn len(&self) -> usize {
24272        (self.end.0 - self.start.0) as usize
24273    }
24274
24275    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24276        (self.start.0..self.end.0).map(MultiBufferRow)
24277    }
24278}
24279
24280impl RowRangeExt for Range<DisplayRow> {
24281    type Row = DisplayRow;
24282
24283    fn len(&self) -> usize {
24284        (self.end.0 - self.start.0) as usize
24285    }
24286
24287    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24288        (self.start.0..self.end.0).map(DisplayRow)
24289    }
24290}
24291
24292/// If select range has more than one line, we
24293/// just point the cursor to range.start.
24294fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24295    if range.start.row == range.end.row {
24296        range
24297    } else {
24298        range.start..range.start
24299    }
24300}
24301pub struct KillRing(ClipboardItem);
24302impl Global for KillRing {}
24303
24304const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24305
24306enum BreakpointPromptEditAction {
24307    Log,
24308    Condition,
24309    HitCondition,
24310}
24311
24312struct BreakpointPromptEditor {
24313    pub(crate) prompt: Entity<Editor>,
24314    editor: WeakEntity<Editor>,
24315    breakpoint_anchor: Anchor,
24316    breakpoint: Breakpoint,
24317    edit_action: BreakpointPromptEditAction,
24318    block_ids: HashSet<CustomBlockId>,
24319    editor_margins: Arc<Mutex<EditorMargins>>,
24320    _subscriptions: Vec<Subscription>,
24321}
24322
24323impl BreakpointPromptEditor {
24324    const MAX_LINES: u8 = 4;
24325
24326    fn new(
24327        editor: WeakEntity<Editor>,
24328        breakpoint_anchor: Anchor,
24329        breakpoint: Breakpoint,
24330        edit_action: BreakpointPromptEditAction,
24331        window: &mut Window,
24332        cx: &mut Context<Self>,
24333    ) -> Self {
24334        let base_text = match edit_action {
24335            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24336            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24337            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24338        }
24339        .map(|msg| msg.to_string())
24340        .unwrap_or_default();
24341
24342        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24343        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24344
24345        let prompt = cx.new(|cx| {
24346            let mut prompt = Editor::new(
24347                EditorMode::AutoHeight {
24348                    min_lines: 1,
24349                    max_lines: Some(Self::MAX_LINES as usize),
24350                },
24351                buffer,
24352                None,
24353                window,
24354                cx,
24355            );
24356            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24357            prompt.set_show_cursor_when_unfocused(false, cx);
24358            prompt.set_placeholder_text(
24359                match edit_action {
24360                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24361                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24362                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24363                },
24364                window,
24365                cx,
24366            );
24367
24368            prompt
24369        });
24370
24371        Self {
24372            prompt,
24373            editor,
24374            breakpoint_anchor,
24375            breakpoint,
24376            edit_action,
24377            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24378            block_ids: Default::default(),
24379            _subscriptions: vec![],
24380        }
24381    }
24382
24383    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24384        self.block_ids.extend(block_ids)
24385    }
24386
24387    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24388        if let Some(editor) = self.editor.upgrade() {
24389            let message = self
24390                .prompt
24391                .read(cx)
24392                .buffer
24393                .read(cx)
24394                .as_singleton()
24395                .expect("A multi buffer in breakpoint prompt isn't possible")
24396                .read(cx)
24397                .as_rope()
24398                .to_string();
24399
24400            editor.update(cx, |editor, cx| {
24401                editor.edit_breakpoint_at_anchor(
24402                    self.breakpoint_anchor,
24403                    self.breakpoint.clone(),
24404                    match self.edit_action {
24405                        BreakpointPromptEditAction::Log => {
24406                            BreakpointEditAction::EditLogMessage(message.into())
24407                        }
24408                        BreakpointPromptEditAction::Condition => {
24409                            BreakpointEditAction::EditCondition(message.into())
24410                        }
24411                        BreakpointPromptEditAction::HitCondition => {
24412                            BreakpointEditAction::EditHitCondition(message.into())
24413                        }
24414                    },
24415                    cx,
24416                );
24417
24418                editor.remove_blocks(self.block_ids.clone(), None, cx);
24419                cx.focus_self(window);
24420            });
24421        }
24422    }
24423
24424    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24425        self.editor
24426            .update(cx, |editor, cx| {
24427                editor.remove_blocks(self.block_ids.clone(), None, cx);
24428                window.focus(&editor.focus_handle);
24429            })
24430            .log_err();
24431    }
24432
24433    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24434        let settings = ThemeSettings::get_global(cx);
24435        let text_style = TextStyle {
24436            color: if self.prompt.read(cx).read_only(cx) {
24437                cx.theme().colors().text_disabled
24438            } else {
24439                cx.theme().colors().text
24440            },
24441            font_family: settings.buffer_font.family.clone(),
24442            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24443            font_size: settings.buffer_font_size(cx).into(),
24444            font_weight: settings.buffer_font.weight,
24445            line_height: relative(settings.buffer_line_height.value()),
24446            ..Default::default()
24447        };
24448        EditorElement::new(
24449            &self.prompt,
24450            EditorStyle {
24451                background: cx.theme().colors().editor_background,
24452                local_player: cx.theme().players().local(),
24453                text: text_style,
24454                ..Default::default()
24455            },
24456        )
24457    }
24458}
24459
24460impl Render for BreakpointPromptEditor {
24461    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24462        let editor_margins = *self.editor_margins.lock();
24463        let gutter_dimensions = editor_margins.gutter;
24464        h_flex()
24465            .key_context("Editor")
24466            .bg(cx.theme().colors().editor_background)
24467            .border_y_1()
24468            .border_color(cx.theme().status().info_border)
24469            .size_full()
24470            .py(window.line_height() / 2.5)
24471            .on_action(cx.listener(Self::confirm))
24472            .on_action(cx.listener(Self::cancel))
24473            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24474            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24475    }
24476}
24477
24478impl Focusable for BreakpointPromptEditor {
24479    fn focus_handle(&self, cx: &App) -> FocusHandle {
24480        self.prompt.focus_handle(cx)
24481    }
24482}
24483
24484fn all_edits_insertions_or_deletions(
24485    edits: &Vec<(Range<Anchor>, String)>,
24486    snapshot: &MultiBufferSnapshot,
24487) -> bool {
24488    let mut all_insertions = true;
24489    let mut all_deletions = true;
24490
24491    for (range, new_text) in edits.iter() {
24492        let range_is_empty = range.to_offset(snapshot).is_empty();
24493        let text_is_empty = new_text.is_empty();
24494
24495        if range_is_empty != text_is_empty {
24496            if range_is_empty {
24497                all_deletions = false;
24498            } else {
24499                all_insertions = false;
24500            }
24501        } else {
24502            return false;
24503        }
24504
24505        if !all_insertions && !all_deletions {
24506            return false;
24507        }
24508    }
24509    all_insertions || all_deletions
24510}
24511
24512struct MissingEditPredictionKeybindingTooltip;
24513
24514impl Render for MissingEditPredictionKeybindingTooltip {
24515    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24516        ui::tooltip_container(cx, |container, cx| {
24517            container
24518                .flex_shrink_0()
24519                .max_w_80()
24520                .min_h(rems_from_px(124.))
24521                .justify_between()
24522                .child(
24523                    v_flex()
24524                        .flex_1()
24525                        .text_ui_sm(cx)
24526                        .child(Label::new("Conflict with Accept Keybinding"))
24527                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24528                )
24529                .child(
24530                    h_flex()
24531                        .pb_1()
24532                        .gap_1()
24533                        .items_end()
24534                        .w_full()
24535                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24536                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24537                        }))
24538                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24539                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24540                        })),
24541                )
24542        })
24543    }
24544}
24545
24546#[derive(Debug, Clone, Copy, PartialEq)]
24547pub struct LineHighlight {
24548    pub background: Background,
24549    pub border: Option<gpui::Hsla>,
24550    pub include_gutter: bool,
24551    pub type_id: Option<TypeId>,
24552}
24553
24554struct LineManipulationResult {
24555    pub new_text: String,
24556    pub line_count_before: usize,
24557    pub line_count_after: usize,
24558}
24559
24560fn render_diff_hunk_controls(
24561    row: u32,
24562    status: &DiffHunkStatus,
24563    hunk_range: Range<Anchor>,
24564    is_created_file: bool,
24565    line_height: Pixels,
24566    editor: &Entity<Editor>,
24567    _window: &mut Window,
24568    cx: &mut App,
24569) -> AnyElement {
24570    h_flex()
24571        .h(line_height)
24572        .mr_1()
24573        .gap_1()
24574        .px_0p5()
24575        .pb_1()
24576        .border_x_1()
24577        .border_b_1()
24578        .border_color(cx.theme().colors().border_variant)
24579        .rounded_b_lg()
24580        .bg(cx.theme().colors().editor_background)
24581        .gap_1()
24582        .block_mouse_except_scroll()
24583        .shadow_md()
24584        .child(if status.has_secondary_hunk() {
24585            Button::new(("stage", row as u64), "Stage")
24586                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24587                .tooltip({
24588                    let focus_handle = editor.focus_handle(cx);
24589                    move |_window, cx| {
24590                        Tooltip::for_action_in(
24591                            "Stage Hunk",
24592                            &::git::ToggleStaged,
24593                            &focus_handle,
24594                            cx,
24595                        )
24596                    }
24597                })
24598                .on_click({
24599                    let editor = editor.clone();
24600                    move |_event, _window, cx| {
24601                        editor.update(cx, |editor, cx| {
24602                            editor.stage_or_unstage_diff_hunks(
24603                                true,
24604                                vec![hunk_range.start..hunk_range.start],
24605                                cx,
24606                            );
24607                        });
24608                    }
24609                })
24610        } else {
24611            Button::new(("unstage", row as u64), "Unstage")
24612                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24613                .tooltip({
24614                    let focus_handle = editor.focus_handle(cx);
24615                    move |_window, cx| {
24616                        Tooltip::for_action_in(
24617                            "Unstage Hunk",
24618                            &::git::ToggleStaged,
24619                            &focus_handle,
24620                            cx,
24621                        )
24622                    }
24623                })
24624                .on_click({
24625                    let editor = editor.clone();
24626                    move |_event, _window, cx| {
24627                        editor.update(cx, |editor, cx| {
24628                            editor.stage_or_unstage_diff_hunks(
24629                                false,
24630                                vec![hunk_range.start..hunk_range.start],
24631                                cx,
24632                            );
24633                        });
24634                    }
24635                })
24636        })
24637        .child(
24638            Button::new(("restore", row as u64), "Restore")
24639                .tooltip({
24640                    let focus_handle = editor.focus_handle(cx);
24641                    move |_window, cx| {
24642                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
24643                    }
24644                })
24645                .on_click({
24646                    let editor = editor.clone();
24647                    move |_event, window, cx| {
24648                        editor.update(cx, |editor, cx| {
24649                            let snapshot = editor.snapshot(window, cx);
24650                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24651                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24652                        });
24653                    }
24654                })
24655                .disabled(is_created_file),
24656        )
24657        .when(
24658            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24659            |el| {
24660                el.child(
24661                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24662                        .shape(IconButtonShape::Square)
24663                        .icon_size(IconSize::Small)
24664                        // .disabled(!has_multiple_hunks)
24665                        .tooltip({
24666                            let focus_handle = editor.focus_handle(cx);
24667                            move |_window, cx| {
24668                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
24669                            }
24670                        })
24671                        .on_click({
24672                            let editor = editor.clone();
24673                            move |_event, window, cx| {
24674                                editor.update(cx, |editor, cx| {
24675                                    let snapshot = editor.snapshot(window, cx);
24676                                    let position =
24677                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24678                                    editor.go_to_hunk_before_or_after_position(
24679                                        &snapshot,
24680                                        position,
24681                                        Direction::Next,
24682                                        window,
24683                                        cx,
24684                                    );
24685                                    editor.expand_selected_diff_hunks(cx);
24686                                });
24687                            }
24688                        }),
24689                )
24690                .child(
24691                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24692                        .shape(IconButtonShape::Square)
24693                        .icon_size(IconSize::Small)
24694                        // .disabled(!has_multiple_hunks)
24695                        .tooltip({
24696                            let focus_handle = editor.focus_handle(cx);
24697                            move |_window, cx| {
24698                                Tooltip::for_action_in(
24699                                    "Previous Hunk",
24700                                    &GoToPreviousHunk,
24701                                    &focus_handle,
24702                                    cx,
24703                                )
24704                            }
24705                        })
24706                        .on_click({
24707                            let editor = editor.clone();
24708                            move |_event, window, cx| {
24709                                editor.update(cx, |editor, cx| {
24710                                    let snapshot = editor.snapshot(window, cx);
24711                                    let point =
24712                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24713                                    editor.go_to_hunk_before_or_after_position(
24714                                        &snapshot,
24715                                        point,
24716                                        Direction::Prev,
24717                                        window,
24718                                        cx,
24719                                    );
24720                                    editor.expand_selected_diff_hunks(cx);
24721                                });
24722                            }
24723                        }),
24724                )
24725            },
24726        )
24727        .into_any_element()
24728}
24729
24730pub fn multibuffer_context_lines(cx: &App) -> u32 {
24731    EditorSettings::try_get(cx)
24732        .map(|settings| settings.excerpt_context_lines)
24733        .unwrap_or(2)
24734        .min(32)
24735}